| … | … | @@ -87,7 +87,15 @@ function image (node, o) { |
| 87 | 87 | const alt = esc(node.alt || '') |
| 88 | 88 | const b = blob(o, node.url || '') |
| 89 | 89 | if (b) { |
| 90 | if (b.mimeType.startsWith('image/')) return '<img src="' + esc(b.src) + '" alt="' + alt + '">' | |
| 90 | if (b.mimeType.startsWith('image/')) { | |
| 91 | // ⛔ A PREVIEW, wrapped in a link to the file itself. An embed rendered at its natural size | |
| 92 | // takes over a timeline — a 4000px photo is not a post, it is a wall — but a preview that | |
| 93 | // cannot be opened has thrown the picture away. The surface constrains `.embed` and the | |
| 94 | // anchor gives the full file back, with no script involved. | |
| 95 | return '<a class="lightbox" href="' + esc(b.src) + '">' + | |
| 96 | '<img class="embed" loading="lazy" src="' + esc(b.src) + '" alt="' + alt + '">' + | |
| 97 | '</a>' | |
| 98 | } | |
| 91 | 99 | // ⛔ `![]()` on a video is deliberate, not a mistake: §3.5 has the embed pipeline consuming |
| 92 | 100 | // images in source order, and a video is the same authoring gesture with different bytes. |
| 93 | 101 | if (b.mimeType.startsWith('video/')) { |
| … | … | @@ -1,6 +1,6 @@ |
| 1 | 1 | { |
| 2 | 2 | "name": "favela-markdown", |
| 3 | "version": "0.1.2", | |
| 3 | "version": "0.1.3", | |
| 4 | 4 | "description": "The P2P-native markdown record layer for favela. A post is a markdown document; atproto and ActivityPub are projections derived from it on read.", |
| 5 | 5 | "type": "module", |
| 6 | 6 | "license": "MIT", |
| … | … | @@ -102,7 +102,10 @@ const resolver = (mimeType, src = '/blob/' + OID) => ({ resolveBlob: () => ({ sr |
| 102 | 102 | |
| 103 | 103 | test('★ an image blob renders an <img> from the surface\'s own src', (t) => { |
| 104 | 104 | const html = render('', resolver('image/png')) |
| 105 | t.ok(/<img src="\/blob\/a3f9[a-f0-9]*" alt="a cat">/.test(html), 'src and alt both survive') | |
| 105 | t.ok(/<img class="embed" loading="lazy" src="\/blob\/a3f9[a-f0-9]*" alt="a cat">/.test(html), | |
| 106 | 'src and alt both survive') | |
| 107 | // ⛔ Wrapped in a link to the file, so a constrained preview does not throw the picture away. | |
| 108 | t.ok(/<a class="lightbox" href="\/blob\//.test(html), 'and it opens full size, with no script') | |
| 106 | 109 | }) |
| 107 | 110 | |
| 108 | 111 | test('★ a video blob renders <video controls>, not a broken image', (t) => { |