feat: add wiki publishing tooling
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
HTML_FILES = [
|
||||
"data/wiki/vulture_shuttle_zh.html",
|
||||
"data/wiki/vulture_shuttle_en.html",
|
||||
"data/wiki/echo_shuttle_zh.html",
|
||||
"data/wiki/echo_shuttle_en.html",
|
||||
"data/wiki/enterprise_shuttle_zh.html",
|
||||
"data/wiki/enterprise_shuttle_en.html",
|
||||
]
|
||||
|
||||
STYLE_RE = re.compile(r"</style>", re.IGNORECASE)
|
||||
SCRIPT_RE = re.compile(r"<script>.*?</script>", re.IGNORECASE | re.DOTALL)
|
||||
|
||||
LIGHTBOX_CSS = """
|
||||
.wiki-article img[data-wiki-asset], .vulture-article img[data-wiki-asset] { cursor: zoom-in; }
|
||||
.wiki-image-lightbox { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; padding: 24px; background: rgba(32,33,34,0.84); z-index: 10000; box-sizing: border-box; }
|
||||
.wiki-image-lightbox[hidden] { display: none; }
|
||||
.wiki-image-lightbox-panel { position: relative; width: min(1120px, 96vw); max-height: 92vh; overflow: auto; margin: 0; padding: 10px; border: 1px solid #a2a9b1; background: #fff; box-shadow: 0 12px 38px rgba(0,0,0,0.35); box-sizing: border-box; }
|
||||
.wiki-image-lightbox-panel img { display: block; width: 100%; height: auto; max-height: 82vh; object-fit: contain; background: #000; }
|
||||
.wiki-image-lightbox-close { position: sticky; top: 0; float: right; width: 30px; height: 30px; margin: -2px -2px 8px 10px; border: 1px solid #a2a9b1; background: #eaecf0; color: #202122; font-weight: bold; line-height: 26px; cursor: pointer; }
|
||||
.wiki-image-lightbox-close:hover, .wiki-image-lightbox-close:focus { background: #fff; }
|
||||
body.wiki-image-lightbox-open { overflow: hidden; }
|
||||
@media (max-width: 820px) { .wiki-image-lightbox { padding: 12px; } .wiki-image-lightbox-panel { width: 98vw; max-height: 94vh; } }
|
||||
""".strip()
|
||||
|
||||
LIGHTBOX_JS = """
|
||||
(function () {
|
||||
function ready(fn) {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', fn, { once: true });
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
function captionFor(image) {
|
||||
var container = image.closest('figure, td, tr, .infobox-image');
|
||||
if (!container) {
|
||||
return image.alt || '';
|
||||
}
|
||||
var caption = container.querySelector('.thumbcaption');
|
||||
return caption ? caption.textContent.trim() : (image.alt || '');
|
||||
}
|
||||
|
||||
function install(article) {
|
||||
if (!article || article.dataset.lightboxReady === '1') {
|
||||
return;
|
||||
}
|
||||
article.dataset.lightboxReady = '1';
|
||||
|
||||
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"><button class="wiki-image-lightbox-close" type="button" aria-label="Close image preview">x</button><img alt=""><figcaption class="thumbcaption"></figcaption></figure>';
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
var previewImage = overlay.querySelector('img');
|
||||
var previewCaption = overlay.querySelector('figcaption');
|
||||
var closeButton = overlay.querySelector('.wiki-image-lightbox-close');
|
||||
|
||||
function closePreview() {
|
||||
overlay.hidden = true;
|
||||
previewImage.removeAttribute('src');
|
||||
previewCaption.textContent = '';
|
||||
document.body.classList.remove('wiki-image-lightbox-open');
|
||||
}
|
||||
|
||||
function openPreview(image, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.stopImmediatePropagation) {
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
previewImage.src = image.currentSrc || image.src;
|
||||
previewImage.alt = image.alt || '';
|
||||
previewCaption.textContent = captionFor(image);
|
||||
overlay.hidden = false;
|
||||
document.body.classList.add('wiki-image-lightbox-open');
|
||||
closeButton.focus();
|
||||
}
|
||||
|
||||
Array.prototype.forEach.call(article.querySelectorAll('img[data-wiki-asset]'), function (image) {
|
||||
if (image.dataset.lightboxBound === '1') {
|
||||
return;
|
||||
}
|
||||
image.dataset.lightboxBound = '1';
|
||||
image.addEventListener('click', function (event) {
|
||||
openPreview(image, event);
|
||||
}, true);
|
||||
});
|
||||
|
||||
article.addEventListener('click', function (event) {
|
||||
var image = event.target.closest && event.target.closest('img[data-wiki-asset]');
|
||||
if (!image || !article.contains(image) || image.closest('.wiki-image-lightbox')) {
|
||||
return;
|
||||
}
|
||||
openPreview(image, event);
|
||||
});
|
||||
|
||||
closeButton.addEventListener('click', closePreview);
|
||||
overlay.addEventListener('click', function (event) {
|
||||
if (event.target === overlay) {
|
||||
closePreview();
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Escape' && !overlay.hidden) {
|
||||
closePreview();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function installAll() {
|
||||
Array.prototype.forEach.call(document.querySelectorAll('.wiki-article, .vulture-article'), install);
|
||||
}
|
||||
|
||||
ready(function () {
|
||||
installAll();
|
||||
if (window.MutationObserver) {
|
||||
var observer = new MutationObserver(installAll);
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
window.setTimeout(installAll, 500);
|
||||
window.setTimeout(installAll, 1500);
|
||||
window.setTimeout(installAll, 3000);
|
||||
});
|
||||
}());
|
||||
""".strip()
|
||||
|
||||
|
||||
def ensure_css(content):
|
||||
if ".wiki-image-lightbox" in content:
|
||||
return content
|
||||
if not STYLE_RE.search(content):
|
||||
raise RuntimeError("No style block found")
|
||||
return STYLE_RE.sub("\n" + LIGHTBOX_CSS + "\n</style>", content, count=1)
|
||||
|
||||
|
||||
def ensure_script(content):
|
||||
script = "<script>\n" + LIGHTBOX_JS + "\n</script>"
|
||||
if SCRIPT_RE.search(content):
|
||||
return SCRIPT_RE.sub(script, content, count=1)
|
||||
return content.rstrip() + "\n" + script + "\n"
|
||||
|
||||
|
||||
def main():
|
||||
repo_root = Path.cwd()
|
||||
changed = 0
|
||||
for relative in HTML_FILES:
|
||||
path = repo_root / relative
|
||||
original = path.read_text(encoding="utf-8")
|
||||
updated = ensure_script(ensure_css(original))
|
||||
if updated != original:
|
||||
path.write_text(updated, encoding="utf-8", newline="\n")
|
||||
changed += 1
|
||||
print(f"lightbox_updated file={relative}")
|
||||
else:
|
||||
print(f"lightbox_unchanged file={relative}")
|
||||
print(f"lightbox_summary html_changed={changed}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user