fix(preview): render HTML files instead of showing literal source
HTML files in the file previewer (archive, transmittal, classifier
popups) were dispatched to the text renderer because 'html'/'htm'
are in shared/preview-lib.js's TEXT_EXTENSIONS (which is shared with
the syntax-highlighting code path). Result: opening an .html file in
preview showed its source as a <pre> block, not the rendered page.
Fix in each tool's popup builder + dispatcher:
- Add 'html' / 'htm' to the iframe branch (alongside pdf), so the
popup ships an <iframe src=blob:...> instead of an empty
#previewContent div. The blob's MIME type from getMimeType()
is already 'text/html', so the browser renders natively.
- Skip the text-render dispatch for html/htm (the iframe is enough).
- Add to the HTML iframe so an arbitrary archived
HTML file cannot run scripts, navigate top, submit forms, or
open popups in the popup-window's origin. PDFs don't need this
since the browser's PDF viewer is sandboxed natively.
classifier/js/preview.js uses a getPreviewType() switch instead of
chained ifs; adds 'html' as its own preview type (checked BEFORE
'text' since html is in TEXT_EXTENSIONS).
mdedit already handled HTML specially (file-tree.js has an isHtml
check); no change there.
TIFF was already rendered via the shared zddc.preview.renderTiff
canvas viewer in all four tools — no change needed for that path.
If TIFF preview appears broken on the live prod server, that's the
v0.0.9-alpha-baked-in image; the fresh stable redeploy fixes it.
This commit is contained in:
parent
8dbd002727
commit
3494053421
3 changed files with 33 additions and 4 deletions
|
|
@ -510,7 +510,9 @@
|
||||||
<h1>${window.app.modules.app.escapeHtml(file.name)}</h1>
|
<h1>${window.app.modules.app.escapeHtml(file.name)}</h1>
|
||||||
<button class="btn" onclick="downloadFile()">Download</button>
|
<button class="btn" onclick="downloadFile()">Download</button>
|
||||||
</div>
|
</div>
|
||||||
${ext === 'pdf' ? '<iframe src="' + url + '"></iframe>' : '<div id="previewContent"><div class="loading">Loading preview...</div></div>'}
|
${(ext === 'pdf' || ext === 'html' || ext === 'htm')
|
||||||
|
? '<iframe src="' + url + '"' + (ext === 'pdf' ? '' : ' sandbox=""') + '></iframe>'
|
||||||
|
: '<div id="previewContent"><div class="loading">Loading preview...</div></div>'}
|
||||||
<script>
|
<script>
|
||||||
var blobUrl = "${url}";
|
var blobUrl = "${url}";
|
||||||
var fileName = "${window.app.modules.app.escapeHtml(file.name).replace(/"/g, '\\"')}";
|
var fileName = "${window.app.modules.app.escapeHtml(file.name).replace(/"/g, '\\"')}";
|
||||||
|
|
@ -552,8 +554,15 @@
|
||||||
filePreviewWindow.focus();
|
filePreviewWindow.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For non-PDF types, render content into the preview window
|
// For non-PDF / non-HTML types, render content into the
|
||||||
if (ext === 'docx') {
|
// preview window. PDF and HTML are already wired up via the
|
||||||
|
// <iframe> in the popup's body (see buildPreviewHtml above);
|
||||||
|
// for HTML this means the page is RENDERED, not shown as
|
||||||
|
// literal source text. The previewBlobUrl carries the right
|
||||||
|
// MIME type ('text/html') so the iframe loads natively.
|
||||||
|
if (ext === 'pdf' || ext === 'html' || ext === 'htm') {
|
||||||
|
// iframe already wired in popup HTML; nothing to do
|
||||||
|
} else if (ext === 'docx') {
|
||||||
await renderDocxInWindow(file);
|
await renderDocxInWindow(file);
|
||||||
} else if (ext === 'xlsx' || ext === 'xls') {
|
} else if (ext === 'xlsx' || ext === 'xls') {
|
||||||
await renderXlsxInWindow(file);
|
await renderXlsxInWindow(file);
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,11 @@
|
||||||
switch (previewType) {
|
switch (previewType) {
|
||||||
case 'pdf':
|
case 'pdf':
|
||||||
return `<iframe src="${blobUrl}#view=FitV"></iframe>`;
|
return `<iframe src="${blobUrl}#view=FitV"></iframe>`;
|
||||||
|
case 'html':
|
||||||
|
// Render the HTML natively (not as literal text). sandbox=""
|
||||||
|
// disables scripts / forms / top-level nav / plugins so an
|
||||||
|
// archived HTML file can't run code in the popup's origin.
|
||||||
|
return `<iframe src="${blobUrl}" sandbox=""></iframe>`;
|
||||||
case 'image':
|
case 'image':
|
||||||
return `<img src="${blobUrl}" alt="${escapeHtml(file.originalFilename)}" />`;
|
return `<img src="${blobUrl}" alt="${escapeHtml(file.originalFilename)}" />`;
|
||||||
case 'text':
|
case 'text':
|
||||||
|
|
@ -305,6 +310,10 @@
|
||||||
* Get preview type from extension
|
* Get preview type from extension
|
||||||
*/
|
*/
|
||||||
function getPreviewType(ext) {
|
function getPreviewType(ext) {
|
||||||
|
// HTML is technically in TEXT_EXTENSIONS (used for editor
|
||||||
|
// syntax-highlighting elsewhere) but for previews we want to
|
||||||
|
// RENDER it, not show source. Check before the text branch.
|
||||||
|
if (ext === 'html' || ext === 'htm') return 'html';
|
||||||
if (PDF_EXTENSIONS.includes(ext)) return 'pdf';
|
if (PDF_EXTENSIONS.includes(ext)) return 'pdf';
|
||||||
if (TIFF_EXTENSIONS.includes(ext)) return 'tiff';
|
if (TIFF_EXTENSIONS.includes(ext)) return 'tiff';
|
||||||
if (IMAGE_EXTENSIONS.includes(ext)) return 'image';
|
if (IMAGE_EXTENSIONS.includes(ext)) return 'image';
|
||||||
|
|
|
||||||
|
|
@ -123,9 +123,18 @@
|
||||||
var safeName = util.escapeHtml(file.name || file.path || 'file');
|
var safeName = util.escapeHtml(file.name || file.path || 'file');
|
||||||
var safeHref = util.escapeHtmlAttribute(url);
|
var safeHref = util.escapeHtmlAttribute(url);
|
||||||
|
|
||||||
|
// PDF and HTML preview natively in an iframe — for HTML this
|
||||||
|
// means the page is RENDERED (not shown as literal source text);
|
||||||
|
// the blob's MIME type ('text/html', see getMimeType) tells the
|
||||||
|
// browser to render. `sandbox=""` on the HTML iframe disables
|
||||||
|
// all dangerous capabilities (scripts, top-level navigation,
|
||||||
|
// forms, plugins, popups) since these are arbitrary archived
|
||||||
|
// files we don't trust to run JS in the parent's origin.
|
||||||
var contentHtml;
|
var contentHtml;
|
||||||
if (ext === 'pdf') {
|
if (ext === 'pdf') {
|
||||||
contentHtml = '<iframe src="' + safeHref + '"></iframe>';
|
contentHtml = '<iframe src="' + safeHref + '"></iframe>';
|
||||||
|
} else if (ext === 'html' || ext === 'htm') {
|
||||||
|
contentHtml = '<iframe src="' + safeHref + '" sandbox=""></iframe>';
|
||||||
} else {
|
} else {
|
||||||
contentHtml = '<div id="previewContent"><div class="loading">Loading preview...</div></div>';
|
contentHtml = '<div id="previewContent"><div class="loading">Loading preview...</div></div>';
|
||||||
}
|
}
|
||||||
|
|
@ -338,7 +347,9 @@
|
||||||
previewWindow.focus();
|
previewWindow.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext === 'docx') {
|
if (ext === 'pdf' || ext === 'html' || ext === 'htm') {
|
||||||
|
// iframe already wired in popup HTML; nothing more to do
|
||||||
|
} else if (ext === 'docx') {
|
||||||
await renderDocxInWindow(file);
|
await renderDocxInWindow(file);
|
||||||
} else if (ext === 'xlsx' || ext === 'xls') {
|
} else if (ext === 'xlsx' || ext === 'xls') {
|
||||||
await renderXlsxInWindow(file);
|
await renderXlsxInWindow(file);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue