diff --git a/internal/web/static/new.js b/internal/web/static/new.js index bee7ce8..1fe0bcf 100644 --- a/internal/web/static/new.js +++ b/internal/web/static/new.js @@ -252,40 +252,48 @@ function extOf(name) { // content into the editor. Title auto-fills only if still blank (house // rule: never overwrite a typed title). const IMAGE_RE = /^image\//; -let previewURL = null; +let previewReader = null; // in-flight FileReader, aborted when the file changes -async function showFileInEditor(file) { +// #171: images preview via a data: URI — the CSP is img-src 'self' data: +// and blob: object URLs would be blocked at render time. +function showFileInEditor(file) { const wrap = document.querySelector('.editor-wrap'); const img = $('file-preview'); if (IMAGE_RE.test(file.type)) { - if (previewURL) URL.revokeObjectURL(previewURL); - previewURL = URL.createObjectURL(file); - img.src = previewURL; - img.alt = file.name; - wrap.classList.add('previewing'); - img.classList.remove('hidden'); + if (previewReader) { try { previewReader.abort(); } catch(e) {} previewReader = null; } + previewReader = new FileReader(); + previewReader.onload = () => { + if (attachedFile !== file) return; // a different file was attached meanwhile + img.src = previewReader.result; // data: URI, allowed by img-src 'self' data: + img.alt = file.name; + wrap.classList.add('previewing'); + img.classList.remove('hidden'); + previewReader = null; + }; + previewReader.onerror = () => { previewReader = null; }; + previewReader.readAsDataURL(file); return; } wrap.classList.remove('previewing'); img.classList.add('hidden'); if (!TEXT_EXTS.has(extOf(file.name))) return; // unknown binary: leave editor alone - try { - const text = await file.text(); + file.text().then(text => { + if (attachedFile !== file) return; if (!content.value.trim()) { content.value = text; updateGutter(); guessLang(); } - } catch (e) {} + }).catch(() => {}); } function clearPreview() { + if (previewReader) { try { previewReader.abort(); } catch(e) {} previewReader = null; } const wrap = document.querySelector('.editor-wrap'); const img = $('file-preview'); wrap.classList.remove('previewing'); img.classList.add('hidden'); img.removeAttribute('src'); - if (previewURL) { URL.revokeObjectURL(previewURL); previewURL = null; } } function setAttachedFile(file) {