(function (app) { 'use strict'; var dom = app.dom; var util = app.util; var filesModule = app.modules.files; // Blob URL cache keyed by file path var blobCache = new Map(); // Current preview popup window reference var previewWindow = null; // Extensions that support rich in-browser preview (in addition to images, // tiff, zip, and text — wired up in isPreviewable below). var PREVIEW_EXTENSIONS = ['pdf', 'docx', 'xlsx', 'xls']; // Use shared image / tiff / text lists from zddc.preview so the four tools // stay in sync on what is previewable. var IMAGE_EXTENSIONS = window.zddc.preview.IMAGE_EXTENSIONS; var TIFF_EXTENSIONS = window.zddc.preview.TIFF_EXTENSIONS; var TEXT_EXTENSIONS = window.zddc.preview.TEXT_EXTENSIONS; // Cache for lazily loaded CDN libraries var loadedLibraries = new Map(); var MIME_TYPES = { 'pdf': 'application/pdf', 'doc': 'application/msword', 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xls': 'application/vnd.ms-excel', 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'ppt': 'application/vnd.ms-powerpoint', 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'txt': 'text/plain', 'csv': 'text/csv', 'html': 'text/html', 'htm': 'text/html', 'xml': 'text/xml', 'json': 'application/json', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'png': 'image/png', 'gif': 'image/gif', 'bmp': 'image/bmp', 'svg': 'image/svg+xml', 'webp': 'image/webp', 'ico': 'image/x-icon', 'zip': 'application/zip', 'mp4': 'video/mp4', 'mp3': 'audio/mpeg', 'wav': 'audio/wav', 'md': 'text/markdown' }; function getMimeType(ext) { return MIME_TYPES[(ext || '').toLowerCase()] || 'application/octet-stream'; } function loadLibrary(url) { if (loadedLibraries.has(url)) { return loadedLibraries.get(url); } var promise = new Promise(function (resolve, reject) { var script = document.createElement('script'); script.src = url; script.onload = resolve; script.onerror = function () { reject(new Error('Failed to load library: ' + url)); }; document.head.appendChild(script); }); loadedLibraries.set(url, promise); return promise; } function isPreviewable(ext) { var lower = (ext || '').toLowerCase(); return PREVIEW_EXTENSIONS.indexOf(lower) !== -1 || IMAGE_EXTENSIONS.indexOf(lower) !== -1 || TIFF_EXTENSIONS.indexOf(lower) !== -1 || TEXT_EXTENSIONS.indexOf(lower) !== -1 || lower === 'zip'; } function hasFileSource(file) { return !!(file.fileHandle || file.zipEntry); } async function getFileArrayBuffer(file) { if (file.fileHandle) { var fileData = await file.fileHandle.getFile(); return fileData.arrayBuffer(); } if (file.zipEntry) { return file.zipEntry.async('arraybuffer'); } throw new Error('No file source available'); } async function getFileBlobUrl(file) { var cacheKey = file.path || file.name || ''; if (blobCache.has(cacheKey)) { return blobCache.get(cacheKey); } var arrayBuffer = await getFileArrayBuffer(file); var mimeType = getMimeType(file.extension); var blob = new Blob([arrayBuffer], { type: mimeType }); var url = URL.createObjectURL(blob); blobCache.set(cacheKey, url); return url; } function cleanupBlobUrls() { blobCache.forEach(function (url) { URL.revokeObjectURL(url); }); blobCache.clear(); } function buildPreviewHtml(file, url) { var ext = (file.extension || '').toLowerCase(); var safeName = util.escapeHtml(file.name || file.path || 'file'); var safeHref = util.escapeHtmlAttribute(url); var contentHtml; if (ext === 'pdf') { contentHtml = ''; } else { contentHtml = '
Loading preview...
'; } return '\n' + '\n' + '\n' + '' + safeName + ' - Preview\n' + '\n' + '\n' + '\n' + '
\n' + '

' + safeName + '

\n' + '\n' + '
\n' + contentHtml + '\n' + '