feat(images): caption / alt text per image, end-to-end#35
Merged
Conversation
Brings 1.x image-title functional parity onto the 2.0 stack across
all three layers, on top of the iManager `files.title` column added
in feature/file-title-column.
Editor — UploadEndpoint:
- New PATCH method: body {fileId, title, tokenName, tokenValue}
→ 200 {"status":"ok","title":"..."} on success, 404 unknown id,
400 missing fileId. Uses the same parseBody() helper as DELETE
so the body works whether the client sends form-urlencoded
PATCH (PHP doesn't populate $_POST for PATCH) or query-string.
- handle() routes PATCH alongside POST and DELETE.
Editor — PagesModule:
- renderUploadedFileRow now emits an inline title input + "save
title" button per file, with data-* attributes (fileId, csrf,
patch-url) the JS handler reads. Layout switched from sprintf
to direct concat for readability.
- renderLegacyImageRow takes an index and emits an input named
`legacy_image_titles[<index>]` so titles persist with the page
save action — the migrated 1.x entries stay in Item.data.images
on purpose (Plan §9: no destructive migration).
- saveAction merges any posted `legacy_image_titles[i]` value back
into the matching slot in `data.images[i].title` before
re-saving the item.
Editor — filepond-init.js:
- New click handler on `.image-list__title-save`: PATCHes the
upload endpoint with {fileId, title, csrf}, surfaces "saving…",
"saved" (auto-clears after 1.5s), or "failed" on the row's
status span.
Frontend — BasicTheme::headlineImage:
- Modern attachments now propagate `$file->title` instead of the
hardcoded ''. Hero/figure templates already wired to render
'INFO' through Sanitizer::markdown so captions support inline
markdown (links, emphasis), matching the 1.x render path.
Manual smoke (PHP built-in server, 64×64 PNG fixture):
POST /editor/api/upload → 200; fileId=11
PATCH /editor/api/upload (title=Captured…) → 200 {"status":"ok"}
DB title set
GET /editor/pages/edit/?page=3 → 200; title-input
prefilled with
saved value; legacy
input named
legacy_image_titles[0]
POST save-page (legacy_image_titles[0]=Edited…)
→ 302; data.images[0]
.title updated
GET /articles/get-started-with-scriptor (cache flushed)
→ "Captured by Phase 14
smoke" in hero caption
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings 1.x image-title functional parity onto the 2.0 stack across all
three layers, on top of the iManager
files.titlecolumn.Editor — UploadEndpoint:
PATCHmethod: body{fileId, title, tokenName, tokenValue}→200
{"status":"ok","title":"..."}on success, 404 unknown id, 400missing fileId. Uses the same
parseBody()helper as DELETE so itworks regardless of whether the client posts the body as
form-urlencoded PATCH or query string.
handle()routes PATCH alongside POST and DELETE.Editor — PagesModule:
renderUploadedFileRowemits an inline title input + "save title"button per file with
data-*attributes the JS handler reads.renderLegacyImageRowtakes an index and emits an input namedlegacy_image_titles[<index>]so titles persist with the page save.Migrated 1.x entries stay in
Item.data.imageson purpose (Plan §9:no destructive migration).
saveActionmerges any postedlegacy_image_titles[i]back intodata.images[i].titlebefore re-saving the item.Editor — filepond-init.js:
.image-list__title-save: PATCHes the uploadendpoint, surfaces "saving…", "saved" (auto-clears after 1.5s), or
"failed" on the row's status span.
Frontend — BasicTheme::headlineImage:
$file->titleinstead of thehardcoded
''. Hero/figure templates already renderINFOthroughSanitizer::markdownso captions support inline markdown (links,emphasis), matching the 1.x path.
Test plan
title=Captured…→ 200{"status":"ok"}; DB has the titlelegacy input present (
legacy_image_titles[0])legacy_image_titles[0]=…→ 302;data.images[0].titleupdated in DB"saved"; reload frontend → caption visible