(function () {
var preview = document.querySelector("[data-source-url][data-file-name][data-content-type]");
if (!preview) {
return;
}
var SMALL_TEXT_BYTES = 50 * 1024;
var LARGE_PREVIEW_BYTES = 500 * 1024;
var state = {
fileName: preview.dataset.fileName || "",
contentType: (preview.dataset.contentType || "").toLowerCase(),
previewKind: preview.dataset.previewKind || "",
sizeBytes: Number(preview.dataset.sizeBytes || 0),
sizeLabel: preview.dataset.fileSize || "",
sourceURL: preview.dataset.sourceUrl || "",
downloadURL: preview.dataset.downloadUrl || "",
iconURL: preview.dataset.iconUrl || "",
sceneURL: preview.dataset.sceneUrl || "",
archiveURL: preview.dataset.archiveUrl || "",
activeMode: "",
defaultMode: "default",
pendingMode: "",
textSource: "",
textLoaded: false,
rawLoaded: false,
prismLoaded: false,
renderLoaded: false,
sceneLoaded: false,
archiveLoaded: false,
archiveUIRendered: false,
archiveData: null,
archiveText: "",
renderFullscreenFallback: false,
confirmedLargeModes: {},
tabs: []
};
var els = {
tabs: preview.querySelector("[data-preview-tabs]"),
modeLabel: preview.querySelector("[data-preview-mode-label]"),
defaultPane: preview.querySelector("[data-default-preview]"),
imagePane: preview.querySelector("[data-image-preview]"),
videoPane: preview.querySelector("[data-video-preview]"),
videoScenesPane: preview.querySelector("[data-video-scenes-preview]"),
browserAudioPane: preview.querySelector("[data-browser-audio-preview]"),
rawPane: preview.querySelector("[data-raw-preview]"),
rawOutput: preview.querySelector("[data-raw-output]"),
codePane: preview.querySelector("[data-code-preview]"),
codeOutput: preview.querySelector("[data-code-output]"),
archiveBrowserPane: preview.querySelector("[data-archive-browser-preview]"),
archivePane: preview.querySelector("[data-archive-preview]"),
archiveOutput: preview.querySelector("[data-archive-output]"),
renderPane: preview.querySelector("[data-render-preview]"),
fullscreenButton: preview.querySelector("[data-render-fullscreen]"),
gatePane: preview.querySelector("[data-large-preview-gate]"),
gateConfirm: preview.querySelector("[data-large-preview-confirm]"),
gateCancel: preview.querySelector("[data-large-preview-cancel]"),
placeholder: preview.querySelector("[data-preview-placeholder]")
};
var fileType = detectFileType();
state.tabs = buildTabs(fileType);
state.defaultMode = chooseDefaultMode(fileType, state.tabs);
bindLargeGate();
bindThemeChanges();
bindRenderFullscreen();
configureMediaSession();
renderTabs();
selectMode(state.defaultMode);
function detectFileType() {
var extension = extensionFor(state.fileName);
var baseType = state.contentType.split(";")[0].trim();
var language = languageFor(extension, baseType);
var isImage = state.previewKind === "image" || baseType.indexOf("image/") === 0 && baseType !== "image/svg+xml";
var isVideo = state.previewKind === "video" || baseType.indexOf("video/") === 0;
var isAudio = state.previewKind === "audio" || baseType.indexOf("audio/") === 0;
var isArchive = Boolean(state.archiveURL) && isArchiveFile(extension, baseType);
return {
extension: extension,
baseType: baseType,
language: language,
isTextLike: Boolean(language),
isHTML: language === "html",
isMarkdown: language === "markdown",
isImage: isImage,
isVideo: isVideo,
isAudio: isAudio,
isArchive: isArchive,
isMobile: window.matchMedia && window.matchMedia("(max-width: 720px), (pointer: coarse)").matches
};
}
function buildTabs(type) {
var tabs = [{ mode: "default", label: "Default" }];
if (type.isImage) {
tabs.push({ mode: "image", label: "Image Preview" });
return tabs;
}
if (type.isVideo) {
tabs.push({ mode: "video", label: "Video Preview" });
if (state.sceneURL && els.videoScenesPane) {
tabs.push({ mode: "scenes", label: "Scenes Preview" });
}
return tabs;
}
if (type.isAudio) {
tabs.push({ mode: "browser-audio", label: "Browser Preview" });
return tabs;
}
if (type.isArchive) {
tabs.push({ mode: "archive-ui", label: "Archive Preview" });
tabs.push({ mode: "archive", label: "Text Tree" });
return tabs;
}
if (type.isTextLike) {
if (type.isHTML || type.isMarkdown) {
tabs.push({ mode: "render", label: "Render Preview" });
}
tabs.push({ mode: "raw", label: "Raw Preview" });
tabs.push({ mode: "code", label: "Code Preview" });
}
return tabs;
}
function chooseDefaultMode(type, tabs) {
if (type.isImage) {
return "image";
}
if (type.isVideo) {
return "video";
}
if (type.isArchive) {
return "archive-ui";
}
if (state.sizeBytes > LARGE_PREVIEW_BYTES) {
if (type.isAudio && hasMode(tabs, "browser-audio")) {
return "browser-audio";
}
return "default";
}
if (type.isAudio) {
return "browser-audio";
}
if (type.isTextLike && state.sizeBytes > SMALL_TEXT_BYTES) {
return "raw";
}
if (type.isMarkdown) {
return "render";
}
if (type.isTextLike) {
return "code";
}
return "default";
}
function renderTabs() {
if (!els.tabs) {
return;
}
els.tabs.innerHTML = "";
state.tabs.forEach(function (tab) {
var button = document.createElement("button");
button.className = "preview-tab";
button.type = "button";
button.dataset.previewTab = tab.mode;
button.textContent = tab.label;
button.addEventListener("click", function () {
selectMode(tab.mode);
});
els.tabs.appendChild(button);
});
}
function selectMode(mode) {
if (!hasMode(state.tabs, mode)) {
mode = "default";
}
if (mode !== "render") {
exitRenderFullscreen();
}
if (requiresLargeConfirmation(mode)) {
showLargeGate(mode);
return;
}
state.activeMode = mode;
updateTabs(mode);
updateRenderFullscreenButton();
hideAllPanes();
setModeLabel(labelForMode(mode));
if (mode === "default") {
show(els.defaultPane);
} else if (mode === "image") {
show(els.imagePane);
} else if (mode === "video") {
show(els.videoPane);
} else if (mode === "scenes") {
show(els.videoScenesPane);
ensureScenesPreview();
} else if (mode === "browser-audio") {
show(els.browserAudioPane);
} else if (mode === "raw") {
show(els.rawPane);
ensureRawPreview();
} else if (mode === "code") {
show(els.codePane);
ensurePrismPreview();
} else if (mode === "archive-ui") {
show(els.archiveBrowserPane);
ensureArchiveBrowserPreview();
} else if (mode === "archive") {
show(els.archivePane);
ensureArchivePreview();
} else if (mode === "render") {
show(els.renderPane);
if (fileType.isMarkdown) {
ensureMarkdownRenderPreview();
} else {
ensureHTMLRenderPreview();
}
}
}
function requiresLargeConfirmation(mode) {
if (state.sizeBytes <= LARGE_PREVIEW_BYTES || state.confirmedLargeModes[mode]) {
return false;
}
return mode === "raw" || mode === "code" || mode === "render";
}
function showLargeGate(mode) {
state.pendingMode = mode;
updateTabs(state.activeMode || state.defaultMode);
updateRenderFullscreenButton(false);
hideAllPanes();
show(els.gatePane);
setModeLabel("Large preview");
}
function bindLargeGate() {
if (els.gateConfirm) {
els.gateConfirm.addEventListener("click", function () {
if (!state.pendingMode) {
return;
}
state.confirmedLargeModes[state.pendingMode] = true;
selectMode(state.pendingMode);
});
}
if (els.gateCancel) {
els.gateCancel.addEventListener("click", function () {
state.pendingMode = "";
selectMode(state.activeMode || state.defaultMode || "default");
});
}
}
function bindThemeChanges() {
var themeSelect = document.querySelector("[data-theme-select]");
if (!themeSelect) {
return;
}
themeSelect.addEventListener("change", function () {
window.setTimeout(function () {
if (!fileType.isMarkdown || !state.renderLoaded) {
return;
}
state.renderLoaded = false;
if (state.activeMode === "render") {
ensureMarkdownRenderPreview();
}
}, 0);
});
}
function bindRenderFullscreen() {
if (!els.fullscreenButton) {
return;
}
els.fullscreenButton.addEventListener("click", function () {
if (isRenderFullscreen()) {
exitRenderFullscreen();
return;
}
enterRenderFullscreen();
});
document.addEventListener("fullscreenchange", updateRenderFullscreenButton);
}
function configureMediaSession() {
if (!("mediaSession" in navigator) || typeof window.MediaMetadata !== "function") {
return;
}
if (!fileType.isAudio && !fileType.isVideo) {
return;
}
var artworkURL = "";
if (fileType.isVideo && els.videoPane) {
artworkURL = els.videoPane.getAttribute("poster") || state.iconURL || "";
} else {
artworkURL = state.iconURL || "";
}
var metadata = {
title: state.fileName || "Warpbox media",
artist: "Warpbox",
album: state.sizeLabel || state.contentType || ""
};
if (artworkURL) {
metadata.artwork = [
{ src: window.Warpbox.absoluteURL(artworkURL), sizes: "512x512", type: "image/png" }
];
}
navigator.mediaSession.metadata = new MediaMetadata(metadata);
}
function ensureTextLoaded() {
if (state.textLoaded) {
return Promise.resolve(state.textSource);
}
showLoading("Loading preview...");
return fetch(state.sourceURL, { credentials: "same-origin" })
.then(function (response) {
if (!response.ok) {
throw new Error("Preview failed");
}
return response.text();
})
.then(function (source) {
state.textSource = source;
state.textLoaded = true;
hide(els.placeholder);
return source;
})
.catch(function (error) {
showError("Preview unavailable");
throw error;
});
}
function ensureRawPreview() {
if (state.rawLoaded) {
return;
}
ensureTextLoaded().then(function (source) {
els.rawOutput.textContent = source;
state.rawLoaded = true;
if (state.activeMode === "raw") {
hide(els.placeholder);
show(els.rawPane);
}
});
}
function ensurePrismPreview() {
if (state.prismLoaded) {
return;
}
showLoading("Loading syntax preview...");
Promise.all([ensureTextLoaded(), loadPrism()])
.then(function (results) {
var source = results[0];
var language = fileType.language;
if (language === "json") {
source = formatJSON(source);
}
els.codeOutput.className = "language-" + language;
els.codeOutput.textContent = source;
if (window.Prism) {
window.Prism.highlightElement(els.codeOutput);
}
state.prismLoaded = true;
if (state.activeMode === "code") {
hide(els.placeholder);
show(els.codePane);
}
})
.catch(function () {
showError("Syntax preview unavailable");
});
}
function ensureHTMLRenderPreview() {
if (state.renderLoaded) {
return;
}
showLoading("Rendering preview...");
ensureTextLoaded()
.then(function (source) {
els.renderPane.srcdoc = withBaseElement(source);
state.renderLoaded = true;
if (state.activeMode === "render") {
hide(els.placeholder);
show(els.renderPane);
}
})
.catch(function () {
showError("Render preview unavailable");
});
}
function ensureMarkdownRenderPreview() {
if (state.renderLoaded) {
return;
}
showLoading("Rendering Markdown...");
Promise.all([ensureTextLoaded(), loadMarkdownLibs()])
.then(function (results) {
var markdown = results[0];
var html = parseMarkdown(markdown);
var clean = window.DOMPurify.sanitize(html);
els.renderPane.srcdoc = markdownDocument(clean);
state.renderLoaded = true;
if (state.activeMode === "render") {
hide(els.placeholder);
show(els.renderPane);
}
})
.catch(function () {
showError("Markdown preview unavailable");
});
}
function showLoading(message) {
if (!els.placeholder) {
return;
}
var text = els.placeholder.querySelector("p");
if (text) {
text.textContent = message;
}
show(els.placeholder);
}
function showError(message) {
hideAllPanes();
var text = els.placeholder && els.placeholder.querySelector("p");
if (text) {
text.textContent = message;
}
show(els.placeholder);
}
function hideAllPanes() {
hide(els.defaultPane);
hide(els.imagePane);
hide(els.videoPane);
hide(els.videoScenesPane);
hide(els.browserAudioPane);
hide(els.rawPane);
hide(els.codePane);
hide(els.archiveBrowserPane);
hide(els.archivePane);
hide(els.renderPane);
hide(els.gatePane);
hide(els.placeholder);
}
function enterRenderFullscreen() {
if (state.activeMode !== "render") {
return;
}
if (preview.requestFullscreen) {
var request = preview.requestFullscreen();
if (request && typeof request.catch === "function") {
request.catch(function () {
state.renderFullscreenFallback = true;
preview.classList.add("is-render-fullscreen");
updateRenderFullscreenButton();
});
}
return;
}
state.renderFullscreenFallback = true;
preview.classList.add("is-render-fullscreen");
updateRenderFullscreenButton();
}
function exitRenderFullscreen() {
if (document.fullscreenElement === preview && document.exitFullscreen) {
var exit = document.exitFullscreen();
if (exit && typeof exit.catch === "function") {
exit.catch(function () {});
}
}
state.renderFullscreenFallback = false;
preview.classList.remove("is-render-fullscreen");
updateRenderFullscreenButton();
}
function isRenderFullscreen() {
return document.fullscreenElement === preview || state.renderFullscreenFallback;
}
function updateRenderFullscreenButton(forceVisible) {
if (!els.fullscreenButton) {
return;
}
var visible = typeof forceVisible === "boolean" ? forceVisible : state.activeMode === "render";
els.fullscreenButton.hidden = !visible;
els.fullscreenButton.textContent = isRenderFullscreen() ? "Exit Full Screen" : "Full Screen";
els.fullscreenButton.setAttribute("aria-pressed", isRenderFullscreen() ? "true" : "false");
}
function updateTabs(mode) {
if (!els.tabs) {
return;
}
Array.prototype.forEach.call(els.tabs.querySelectorAll("[data-preview-tab]"), function (button) {
button.classList.toggle("is-active", button.dataset.previewTab === mode);
});
}
function show(element) {
if (element) {
element.hidden = false;
}
}
function hide(element) {
if (element) {
element.hidden = true;
}
}
function setModeLabel(label) {
if (els.modeLabel) {
els.modeLabel.textContent = label;
}
}
function hasMode(tabs, mode) {
return tabs.some(function (tab) {
return tab.mode === mode;
});
}
function labelForMode(mode) {
var labels = {
"default": "Default",
"image": "Image preview",
"video": "Video preview",
"scenes": "Scenes preview",
"browser-audio": "Browser preview",
"raw": "Raw preview",
"code": "Code preview",
"archive-ui": "Archive preview",
"archive": "Archive preview",
"render": "Render preview"
};
return labels[mode] || "Preview";
}
function ensureScenesPreview() {
if (state.sceneLoaded || !els.videoScenesPane) {
return;
}
var src = els.videoScenesPane.dataset.sceneSrc || state.sceneURL;
if (!src) {
return;
}
els.videoScenesPane.src = src;
state.sceneLoaded = true;
}
function ensureArchivePreview() {
if (state.archiveLoaded || !els.archiveOutput || !state.archiveURL) {
return;
}
ensureArchiveData()
.then(function () {
var text = state.archiveText || archiveDataToText(state.archiveData);
els.archiveOutput.textContent = text;
state.archiveLoaded = true;
hide(els.placeholder);
show(els.archivePane);
})
.catch(function () {
showError("Archive preview could not be loaded.");
});
}
function ensureArchiveBrowserPreview() {
if (state.archiveUIRendered || !els.archiveBrowserPane || !state.archiveURL) {
return;
}
ensureArchiveData()
.then(function () {
renderArchiveBrowser(state.archiveData);
state.archiveUIRendered = true;
hide(els.placeholder);
show(els.archiveBrowserPane);
})
.catch(function () {
showError("Archive preview could not be loaded.");
});
}
function ensureArchiveData() {
if (state.archiveData || state.archiveText) {
return Promise.resolve();
}
showLoading("Loading archive contents...");
return fetch(state.archiveURL, { credentials: "same-origin" })
.then(function (response) {
if (!response.ok) {
throw new Error("Archive preview could not be loaded.");
}
return response.text();
})
.then(function (text) {
try {
state.archiveData = JSON.parse(text);
} catch (error) {
state.archiveText = text;
}
});
}
function renderArchiveBrowser(data) {
if (!els.archiveBrowserPane) {
return;
}
els.archiveBrowserPane.innerHTML = "";
if (!data || !data.root) {
var fallback = document.createElement("pre");
fallback.className = "archive-browser-legacy";
fallback.textContent = state.archiveText || "Archive preview is unavailable.";
els.archiveBrowserPane.appendChild(fallback);
return;
}
var header = document.createElement("div");
header.className = "archive-browser-header";
header.innerHTML = "";
header.querySelector("strong").textContent = data.name || state.fileName || "Archive";
header.querySelector("span").textContent = [
data.type || "Archive",
formatArchiveCount(data.fileCount, "file"),
formatArchiveCount(data.folderCount, "folder"),
formatBytes(data.uncompressedSize || 0)
].filter(Boolean).join(" ยท ");
els.archiveBrowserPane.appendChild(header);
var tree = document.createElement("div");
tree.className = "archive-tree";
var items = data.root.items || [];
if (items.length === 0) {
var emptyTree = document.createElement("p");
emptyTree.className = "archive-browser-empty";
emptyTree.textContent = "This archive is empty.";
tree.appendChild(emptyTree);
} else {
items.forEach(function (item) {
tree.appendChild(renderArchiveNode(item, 0));
});
}
els.archiveBrowserPane.appendChild(tree);
}
function renderArchiveNode(node, depth) {
var row = document.createElement(node.dir ? "details" : "div");
row.className = node.dir ? "archive-node archive-folder" : "archive-node archive-file";
if (node.dir && depth < 1) {
row.open = true;
}
var summary = document.createElement(node.dir ? "summary" : "div");
summary.className = "archive-node-row";
summary.style.paddingLeft = (0.45 + depth * 1.15).toFixed(2) + "rem";
if (node.dir) {
summary.appendChild(createArchiveChevron());
} else {
var spacer = document.createElement("span");
spacer.className = "archive-chevron-spacer";
summary.appendChild(spacer);
}
summary.appendChild(createArchiveIcon(node.icon || (node.dir ? "folder" : "file")));
var name = document.createElement("span");
name.className = "archive-node-name";
name.textContent = node.name + (node.dir ? "/" : "");
summary.appendChild(name);
if (!node.dir) {
var size = document.createElement("span");
size.className = "archive-node-size";
size.textContent = formatBytes(node.size || 0);
summary.appendChild(size);
}
row.appendChild(summary);
if (node.dir) {
(node.items || []).forEach(function (child) {
row.appendChild(renderArchiveNode(child, depth + 1));
});
}
return row;
}
function createArchiveChevron() {
var chevron = document.createElement("span");
chevron.className = "archive-chevron";
chevron.setAttribute("aria-hidden", "true");
chevron.innerHTML = '';
return chevron;
}
function createArchiveIcon(icon) {
var element = document.createElement("span");
element.className = "archive-file-icon archive-file-icon-" + icon;
element.setAttribute("aria-hidden", "true");
element.innerHTML = '';
var retroURL = archiveRetroIconURL(icon);
if (retroURL) {
var retro = document.createElement("img");
retro.className = "archive-retro-icon";
retro.src = retroURL;
retro.alt = "";
retro.decoding = "async";
retro.loading = "lazy";
element.appendChild(retro);
}
return element;
}
function archiveDataToText(data) {
if (!data || !data.root) {
return state.archiveText || "";
}
var lines = [
"Archive preview",
"Name: " + (data.name || state.fileName || "Archive"),
"Type: " + (data.type || "Archive"),
"Entries: " + (data.fileCount || 0) + " files, " + (data.folderCount || 0) + " folders",
"Uncompressed size: " + formatBytes(data.uncompressedSize || 0),
"",
"."
];
appendArchiveTextLines(lines, data.root.items || [], "");
if (!(data.root.items || []).length) {
lines.push("(empty archive)");
}
return lines.join("\n");
}
function appendArchiveTextLines(lines, items, prefix) {
items.forEach(function (item, index) {
var last = index === items.length - 1;
var branch = last ? "`-- " : "|-- ";
var nextPrefix = prefix + (last ? " " : "| ");
var label = item.dir ? "[DIR] " + item.name + "/" : "[" + (item.icon || "file").toUpperCase() + "] " + item.name + " (" + formatBytes(item.size || 0) + ")";
lines.push(prefix + branch + label);
if (item.dir) {
appendArchiveTextLines(lines, item.items || [], nextPrefix);
}
});
}
function archiveIconSVG(icon) {
var icons = {
folder: '',
img: '',
vid: '',
aud: '',
txt: '',
code: '',
arc: '',
file: ''
};
return icons[icon] || icons.file;
}
function archiveRetroIconURL(icon) {
var base = "/static/file-icons/retro/";
var icons = {
folder: "directory_open_file_mydocs-4.png",
img: "shimgvw.dll_14_1-2.png",
vid: "wmploc.dll_14_504-2.png",
aud: "wmploc.dll_14_610-2.png",
txt: "shell32.dll_14_151-2.png",
code: "mshtml.dll_14_2660-2.png",
arc: "zipfldr.dll_14_101-2.png",
file: "shell32.dll_14_152-2.png"
};
return base + (icons[icon] || icons.file);
}
function formatArchiveCount(value, label) {
value = Number(value || 0);
return value + " " + label + (value === 1 ? "" : "s");
}
function formatBytes(value) {
value = Number(value || 0);
if (value < 1024) {
return value + " B";
}
var units = ["KiB", "MiB", "GiB", "TiB"];
var size = value / 1024;
for (var i = 0; i < units.length; i++) {
if (size < 1024 || i === units.length - 1) {
return size.toFixed(1) + " " + units[i];
}
size /= 1024;
}
return value + " B";
}
function loadPrism() {
if (window.Prism) {
return Promise.resolve();
}
window.Prism = window.Prism || {};
window.Prism.manual = true;
return Promise.all([
loadStyle("/static/lib/prismjs/prism.css"),
loadScript("/static/lib/prismjs/prism.js")
]);
}
function loadMarkdownLibs() {
if (window.marked && window.DOMPurify) {
return Promise.resolve();
}
return Promise.all([
loadScript("/static/lib/markdown/marked.umd.js"),
loadScript("/static/lib/markdown/purify.min.js")
]);
}
function loadScript(src) {
return new Promise(function (resolve, reject) {
var existing = document.querySelector('script[src="' + src + '"]');
if (existing) {
if (existing.dataset.loaded === "true") {
resolve();
return;
}
existing.addEventListener("load", resolve, { once: true });
existing.addEventListener("error", reject, { once: true });
return;
}
var script = document.createElement("script");
script.async = true;
script.src = src;
script.addEventListener("load", function () {
script.dataset.loaded = "true";
resolve();
}, { once: true });
script.addEventListener("error", reject, { once: true });
document.head.appendChild(script);
});
}
function loadStyle(href) {
if (document.querySelector('link[href="' + href + '"]')) {
return Promise.resolve();
}
return new Promise(function (resolve, reject) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = href;
link.addEventListener("load", resolve, { once: true });
link.addEventListener("error", reject, { once: true });
document.head.appendChild(link);
});
}
function parseMarkdown(source) {
if (window.marked && typeof window.marked.parse === "function") {
return window.marked.parse(source);
}
if (window.marked && window.marked.marked && typeof window.marked.marked.parse === "function") {
return window.marked.marked.parse(source);
}
throw new Error("Marked unavailable");
}
function markdownDocument(body) {
var theme = currentTheme();
var base = '