@geekity/cms 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -52
- package/admin/pages/documents/editor.njk +120 -0
- package/admin/pages/documents/syndication.njk +110 -0
- package/admin/pages/federation/followers.njk +7 -0
- package/admin/pages/media/library.njk +4 -3
- package/admin/pages/settings/general.njk +44 -0
- package/admin/static/admin.css +44 -0
- package/dist/admin/documents.d.ts +104 -0
- package/dist/admin/documents.d.ts.map +1 -1
- package/dist/admin/documents.js +220 -55
- package/dist/admin/documents.js.map +1 -1
- package/dist/admin/enclosure-field.d.ts +91 -0
- package/dist/admin/enclosure-field.d.ts.map +1 -0
- package/dist/admin/enclosure-field.js +282 -0
- package/dist/admin/enclosure-field.js.map +1 -0
- package/dist/admin/federation.d.ts +15 -0
- package/dist/admin/federation.d.ts.map +1 -1
- package/dist/admin/federation.js +19 -0
- package/dist/admin/federation.js.map +1 -1
- package/dist/admin/media.d.ts +7 -2
- package/dist/admin/media.d.ts.map +1 -1
- package/dist/admin/media.js +4 -2
- package/dist/admin/media.js.map +1 -1
- package/dist/admin/menu.d.ts.map +1 -1
- package/dist/admin/menu.js +3 -0
- package/dist/admin/menu.js.map +1 -1
- package/dist/admin/photo-field.d.ts +39 -0
- package/dist/admin/photo-field.d.ts.map +1 -0
- package/dist/admin/photo-field.js +91 -0
- package/dist/admin/photo-field.js.map +1 -0
- package/dist/admin/preview.d.ts.map +1 -1
- package/dist/admin/preview.js +6 -1
- package/dist/admin/preview.js.map +1 -1
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +4 -0
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/settings-general.d.ts.map +1 -1
- package/dist/admin/settings-general.js +36 -2
- package/dist/admin/settings-general.js.map +1 -1
- package/dist/admin/settings-page.d.ts.map +1 -1
- package/dist/admin/settings-page.js +1 -2
- package/dist/admin/settings-page.js.map +1 -1
- package/dist/admin/settings.d.ts +26 -0
- package/dist/admin/settings.d.ts.map +1 -1
- package/dist/admin/settings.js +88 -2
- package/dist/admin/settings.js.map +1 -1
- package/dist/admin/syndication-targets.d.ts +57 -0
- package/dist/admin/syndication-targets.d.ts.map +1 -0
- package/dist/admin/syndication-targets.js +266 -0
- package/dist/admin/syndication-targets.js.map +1 -0
- package/dist/admin/templates.d.ts +1 -0
- package/dist/admin/templates.d.ts.map +1 -1
- package/dist/admin/templates.js +1 -0
- package/dist/admin/templates.js.map +1 -1
- package/dist/admin/uploads.d.ts +13 -2
- package/dist/admin/uploads.d.ts.map +1 -1
- package/dist/admin/uploads.js +23 -5
- package/dist/admin/uploads.js.map +1 -1
- package/dist/config.d.ts +17 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -7
- package/dist/config.js.map +1 -1
- package/dist/content/citation.d.ts +36 -0
- package/dist/content/citation.d.ts.map +1 -0
- package/dist/content/citation.js +31 -0
- package/dist/content/citation.js.map +1 -0
- package/dist/content/enclosure.d.ts +69 -0
- package/dist/content/enclosure.d.ts.map +1 -0
- package/dist/content/enclosure.js +165 -0
- package/dist/content/enclosure.js.map +1 -0
- package/dist/content/index.d.ts +5 -1
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +2 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/media.d.ts +15 -2
- package/dist/content/media.d.ts.map +1 -1
- package/dist/content/media.js +92 -9
- package/dist/content/media.js.map +1 -1
- package/dist/content/photo.d.ts +45 -0
- package/dist/content/photo.d.ts.map +1 -0
- package/dist/content/photo.js +55 -0
- package/dist/content/photo.js.map +1 -0
- package/dist/content/post-type.d.ts +20 -8
- package/dist/content/post-type.d.ts.map +1 -1
- package/dist/content/post-type.js +17 -0
- package/dist/content/post-type.js.map +1 -1
- package/dist/federation/article.d.ts.map +1 -1
- package/dist/federation/article.js +93 -10
- package/dist/federation/article.js.map +1 -1
- package/dist/federation/citations.d.ts +38 -0
- package/dist/federation/citations.d.ts.map +1 -0
- package/dist/federation/citations.js +98 -0
- package/dist/federation/citations.js.map +1 -0
- package/dist/federation/delivery.d.ts.map +1 -1
- package/dist/federation/delivery.js +79 -31
- package/dist/federation/delivery.js.map +1 -1
- package/dist/images/alt-text.d.ts +6 -0
- package/dist/images/alt-text.d.ts.map +1 -1
- package/dist/images/alt-text.js +10 -0
- package/dist/images/alt-text.js.map +1 -1
- package/dist/images/icons.d.ts +5 -0
- package/dist/images/icons.d.ts.map +1 -1
- package/dist/images/icons.js +13 -8
- package/dist/images/icons.js.map +1 -1
- package/dist/images/paths.d.ts +1 -1
- package/dist/images/paths.d.ts.map +1 -1
- package/dist/images/paths.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -4
- package/dist/index.js.map +1 -1
- package/dist/indieauth/bearer.d.ts +6 -1
- package/dist/indieauth/bearer.d.ts.map +1 -1
- package/dist/indieauth/bearer.js +39 -12
- package/dist/indieauth/bearer.js.map +1 -1
- package/dist/indieauth/discovery.d.ts +9 -4
- package/dist/indieauth/discovery.d.ts.map +1 -1
- package/dist/indieauth/discovery.js +18 -7
- package/dist/indieauth/discovery.js.map +1 -1
- package/dist/micropub/create.d.ts +56 -0
- package/dist/micropub/create.d.ts.map +1 -0
- package/dist/micropub/create.js +200 -0
- package/dist/micropub/create.js.map +1 -0
- package/dist/micropub/endpoint.d.ts +21 -0
- package/dist/micropub/endpoint.d.ts.map +1 -0
- package/dist/micropub/endpoint.js +353 -0
- package/dist/micropub/endpoint.js.map +1 -0
- package/dist/micropub/media.d.ts +14 -0
- package/dist/micropub/media.d.ts.map +1 -0
- package/dist/micropub/media.js +93 -0
- package/dist/micropub/media.js.map +1 -0
- package/dist/micropub/update.d.ts +44 -0
- package/dist/micropub/update.d.ts.map +1 -0
- package/dist/micropub/update.js +133 -0
- package/dist/micropub/update.js.map +1 -0
- package/dist/web/assets.d.ts +14 -0
- package/dist/web/assets.d.ts.map +1 -1
- package/dist/web/assets.js +56 -1
- package/dist/web/assets.js.map +1 -1
- package/dist/web/context.d.ts +68 -3
- package/dist/web/context.d.ts.map +1 -1
- package/dist/web/context.js +56 -1
- package/dist/web/context.js.map +1 -1
- package/dist/web/feed-atom.d.ts.map +1 -1
- package/dist/web/feed-atom.js +20 -0
- package/dist/web/feed-atom.js.map +1 -1
- package/dist/web/feed-item.d.ts +19 -0
- package/dist/web/feed-item.d.ts.map +1 -1
- package/dist/web/feed-item.js +22 -0
- package/dist/web/feed-item.js.map +1 -1
- package/dist/web/feed-json.d.ts +13 -0
- package/dist/web/feed-json.d.ts.map +1 -1
- package/dist/web/feed-json.js +15 -0
- package/dist/web/feed-json.js.map +1 -1
- package/dist/web/feed-rss.d.ts.map +1 -1
- package/dist/web/feed-rss.js +59 -2
- package/dist/web/feed-rss.js.map +1 -1
- package/dist/web/feed-xml.d.ts +7 -1
- package/dist/web/feed-xml.d.ts.map +1 -1
- package/dist/web/feed-xml.js +8 -2
- package/dist/web/feed-xml.js.map +1 -1
- package/dist/web/feeds.d.ts +1 -1
- package/dist/web/feeds.d.ts.map +1 -1
- package/dist/web/feeds.js +6 -0
- package/dist/web/feeds.js.map +1 -1
- package/dist/web/index.d.ts +4 -1
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +2 -0
- package/dist/web/index.js.map +1 -1
- package/dist/web/license.d.ts +94 -0
- package/dist/web/license.d.ts.map +1 -0
- package/dist/web/license.js +116 -0
- package/dist/web/license.js.map +1 -0
- package/dist/web/oembed.d.ts.map +1 -1
- package/dist/web/oembed.js +1 -2
- package/dist/web/oembed.js.map +1 -1
- package/dist/web/render.d.ts +15 -0
- package/dist/web/render.d.ts.map +1 -1
- package/dist/web/render.js +27 -2
- package/dist/web/render.js.map +1 -1
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +10 -6
- package/dist/web/routes.js.map +1 -1
- package/dist/web/share-image.d.ts +7 -7
- package/dist/web/share-image.d.ts.map +1 -1
- package/dist/web/share-image.js +8 -7
- package/dist/web/share-image.js.map +1 -1
- package/dist/webmention/index.d.ts +2 -0
- package/dist/webmention/index.d.ts.map +1 -1
- package/dist/webmention/index.js +1 -0
- package/dist/webmention/index.js.map +1 -1
- package/dist/webmention/service.d.ts.map +1 -1
- package/dist/webmention/service.js +96 -18
- package/dist/webmention/service.js.map +1 -1
- package/dist/webmention/syndication.d.ts +135 -0
- package/dist/webmention/syndication.d.ts.map +1 -0
- package/dist/webmention/syndication.js +337 -0
- package/dist/webmention/syndication.js.map +1 -0
- package/package.json +1 -1
- package/themes/default/README.md +121 -37
- package/themes/default/layouts/base.njk +3 -4
- package/themes/default/layouts/post.njk +23 -6
- package/themes/default/partials/citations.njk +17 -0
- package/themes/default/partials/jsonld.njk +15 -6
- package/themes/default/partials/photos.njk +10 -0
- package/themes/default/partials/post-list.njk +7 -0
- package/themes/default/partials/recording.njk +41 -0
- package/themes/default/src/style.css +25 -0
- package/themes/default/static/style.css +41 -0
package/README.md
CHANGED
|
@@ -1185,6 +1185,113 @@ answers 404 or 410 — takes it away. Closing rules do not apply: a post that
|
|
|
1185
1185
|
stopped taking comments still hears about a page that links to it, exactly as it
|
|
1186
1186
|
still hears a fediverse reply.
|
|
1187
1187
|
|
|
1188
|
+
### Syndication targets
|
|
1189
|
+
|
|
1190
|
+
Some services copy a post when it links to them and sends them a webmention,
|
|
1191
|
+
and answer with the address of the copy. IndieNews lists posts about the
|
|
1192
|
+
IndieWeb; Bridgy Publish posts to Mastodon, Bluesky, GitHub and Flickr. The
|
|
1193
|
+
CMS knows none of them by name. A site lists the ones it uses on the admin's
|
|
1194
|
+
**Posts > Syndication** screen (`/admin/syndication`), which reads
|
|
1195
|
+
and writes `content/_data/syndicationTargets.json`. The file stays the source of
|
|
1196
|
+
truth, so it can still be edited by hand, and it looks like this:
|
|
1197
|
+
|
|
1198
|
+
```json
|
|
1199
|
+
[
|
|
1200
|
+
{
|
|
1201
|
+
"id": "indienews",
|
|
1202
|
+
"name": "IndieNews",
|
|
1203
|
+
"url": "https://news.indieweb.org/en",
|
|
1204
|
+
"tag": "indienews"
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
"id": "mastodon",
|
|
1208
|
+
"name": "Mastodon",
|
|
1209
|
+
"url": "https://brid.gy/publish/mastodon"
|
|
1210
|
+
}
|
|
1211
|
+
]
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
| Key | What it is |
|
|
1215
|
+
| ----------- | --------------------------------------------------------------------------------------------- |
|
|
1216
|
+
| `id` | What a post's `syndicate-to` lists. Letters, digits, `.`, `-` and `_`. |
|
|
1217
|
+
| `name` | What the editor's checkbox and the post's link say. |
|
|
1218
|
+
| `url` | The page the post links to and sends its webmention to. May hold `{lang}`. |
|
|
1219
|
+
| `tag` | Optional. A post carrying this tag is sent to the target without listing it. |
|
|
1220
|
+
| `languages` | Optional. The language tags the target takes posts in. A post in any other language skips it. |
|
|
1221
|
+
|
|
1222
|
+
An entry missing any of the first three, repeating an id, or with a `languages`
|
|
1223
|
+
value that is not a list of language tags, is ignored. It is reported in the log
|
|
1224
|
+
when the site starts, and the Syndication screen shows it with its problem so it
|
|
1225
|
+
can be fixed or removed there. No file means no targets.
|
|
1226
|
+
|
|
1227
|
+
The screen has a panel for each entry, in file order, and an **Add a target**
|
|
1228
|
+
form. A save is checked by the same rules the file is read by: a field that
|
|
1229
|
+
breaks one is marked on the form and the file is left as it was. A save that
|
|
1230
|
+
passes is written atomically, and the editor's **Syndicate to** checkboxes and
|
|
1231
|
+
Micropub's `q=syndicate-to` offer the change on the next request. A save or
|
|
1232
|
+
remove is refused when the entry changed in the file since the page was drawn.
|
|
1233
|
+
A file that is not a JSON list is shown with its problem and never saved over.
|
|
1234
|
+
To keep the default theme's old IndieNews link, add a target with the id
|
|
1235
|
+
`indienews`, the url `https://news.indieweb.org/{lang}` and the tag `indienews`.
|
|
1236
|
+
|
|
1237
|
+
Some targets have a page per language. IndieNews has `news.indieweb.org/en`,
|
|
1238
|
+
`/de`, `/fr` and more. Declare one target and put `{lang}` where the language
|
|
1239
|
+
goes:
|
|
1240
|
+
|
|
1241
|
+
```json
|
|
1242
|
+
{
|
|
1243
|
+
"id": "indienews",
|
|
1244
|
+
"name": "IndieNews",
|
|
1245
|
+
"url": "https://news.indieweb.org/{lang}",
|
|
1246
|
+
"tag": "indienews",
|
|
1247
|
+
"languages": ["en", "de", "fr"]
|
|
1248
|
+
}
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
The CMS fills `{lang}` with the post's language: its `lang` front matter, or the
|
|
1252
|
+
site's language when the post names none. With `languages`, a post in a
|
|
1253
|
+
language the list does not name neither links to the target nor notifies it. A
|
|
1254
|
+
regional tag counts as its language, so a `de-AT` post goes to
|
|
1255
|
+
`news.indieweb.org/de`, and `{lang}` takes the tag from the list. Without
|
|
1256
|
+
`languages`, `{lang}` takes the post's own tag as written, region and all.
|
|
1257
|
+
|
|
1258
|
+
A post selects targets in one of two ways:
|
|
1259
|
+
|
|
1260
|
+
- **By listing them.** The post editor has a **Syndicate to** checkbox for each
|
|
1261
|
+
target, and saving writes the ticked ids into the front matter as
|
|
1262
|
+
`syndicate-to: [indienews, mastodon]`. An id no target declares is kept as
|
|
1263
|
+
written.
|
|
1264
|
+
- **By its tags.** A post tagged `indienews` is sent to the target whose `tag`
|
|
1265
|
+
is `indienews`, as the WordPress IndieNews plugin did.
|
|
1266
|
+
|
|
1267
|
+
The default theme links to each selected target at the start of the Published
|
|
1268
|
+
line, inside the post's `h-entry`, as `<a class="u-syndication"
|
|
1269
|
+
href="https://news.indieweb.org/en">IndieNews</a>`. That link is what IndieNews
|
|
1270
|
+
and Bridgy Publish check for when they fetch the post. When the post is
|
|
1271
|
+
published or updated, the sender adds each selected target to the pages it
|
|
1272
|
+
notifies, the same way it adds the post a reply answers. Nothing is sent while a
|
|
1273
|
+
page is served.
|
|
1274
|
+
|
|
1275
|
+
A target that answers `201` or `202` with a `Location` header has made a copy.
|
|
1276
|
+
The address is kept in `content/_data/syndication.json`, keyed by the post's
|
|
1277
|
+
permalink (decision-26), and the theme prints it after the dates as **Also on**
|
|
1278
|
+
with a `u-syndication` link. A copy made by hand goes in the post's own front
|
|
1279
|
+
matter, and is printed the same way:
|
|
1280
|
+
|
|
1281
|
+
```yaml
|
|
1282
|
+
syndication:
|
|
1283
|
+
- https://mastodon.social/@me/113000000000000000
|
|
1284
|
+
```
|
|
1285
|
+
|
|
1286
|
+
Removing a target from `syndicate-to`, or removing its tag, removes the link.
|
|
1287
|
+
The sender then tells the target, as it tells any page a post stops linking to,
|
|
1288
|
+
and the copy is dropped from `syndication.json`. IndieNews takes the post down
|
|
1289
|
+
when it finds the link gone. Drafting or trashing the post does the same.
|
|
1290
|
+
|
|
1291
|
+
The posts table on `/admin/federation` lists each selected target with how its
|
|
1292
|
+
last webmention went and a link to its copy, and **Resend** sends to the targets
|
|
1293
|
+
again.
|
|
1294
|
+
|
|
1188
1295
|
## Email
|
|
1189
1296
|
|
|
1190
1297
|
The CMS sends its mail through one service and one seam. Everything that will
|
|
@@ -1671,53 +1778,53 @@ that ship inside the package, deliberately outside the theme search path: a
|
|
|
1671
1778
|
site's theme may override any public template, and must not be able to
|
|
1672
1779
|
shadow the login form.
|
|
1673
1780
|
|
|
1674
|
-
| Route | What it does
|
|
1675
|
-
| ------------------------------------------------ |
|
|
1676
|
-
| `/admin` | The dashboard: counts, the five most recent posts, the follower count.
|
|
1677
|
-
| `/admin/posts`, `/admin/pages` | The listings and the editors.
|
|
1678
|
-
| `/admin/tags`, `/admin/categories` | Every term in use, with rename, merge and delete.
|
|
1679
|
-
| `/admin/tags/rename`, `/admin/categories/rename` | `POST` only. Renames a term, or merges it into one that exists.
|
|
1680
|
-
| `/admin/tags/delete`, `/admin/categories/delete` | `POST` only. Takes a term out of every file.
|
|
1681
|
-
| `/admin/navigation` | Navigation > Menus: every menu the site holds. `POST` saves one menu's items.
|
|
1682
|
-
| `/admin/navigation/add` | `POST` only. Adds an empty menu under the name the form gives.
|
|
1683
|
-
| `/admin/navigation/delete` | `POST` only. Deletes one menu the active theme renders nowhere.
|
|
1684
|
-
| `/admin/media` | Everything under `content/uploads`, with the URL, the Markdown and what uses it.
|
|
1685
|
-
| `/admin/media/upload` | `POST` only. Stores one file by the rules the editor's upload enforces.
|
|
1686
|
-
| `/admin/media/delete` | `POST` only. Deletes one upload, asking first when a document points at it.
|
|
1687
|
-
| `/admin/media/alt` | `POST` only. Sets a picture's alt text, or marks it decorative, in `media.json`.
|
|
1688
|
-
| `/admin/comments` | Pending, approved and spam, with approve, spam, delete and reply.
|
|
1689
|
-
| `/admin/comments/moderate` | `POST` only. Approves one comment, files it as spam, or deletes it.
|
|
1690
|
-
| `/admin/comments/reply` | `POST` only. Posts an approved reply under the comment it answers.
|
|
1691
|
-
| `/admin/messages` | The contact form's inbox, with a Spam list beside it.
|
|
1692
|
-
| `/admin/messages/read` | `POST` only. Marks one message read, or unread again.
|
|
1693
|
-
| `/admin/messages/delete` | `POST` only. Deletes one message, and its file with it.
|
|
1694
|
-
| `/admin/appearance/themes` | Appearance > Themes: the themes on disk. `POST` activates the one named.
|
|
1695
|
-
| `/admin/tools` | Tools > Content index: what the index holds, and the button that rebuilds it.
|
|
1696
|
-
| `/admin/tools/rebuild-index` | `POST` only. Offers the rebuild, then reads every file again on the live site.
|
|
1697
|
-
| `/admin/settings` | Settings > General: title, tagline, author, base URL, time zone, language, locale.
|
|
1698
|
-
| `/admin/settings/reading` | What the homepage displays, posts per page, the notify server.
|
|
1699
|
-
| `/admin/settings/permalinks` | The tag and category bases, and the archive redirects already recorded.
|
|
1700
|
-
| `/admin/settings/discussion` | Comments and the closing window, webmentions, and the Akismet key.
|
|
1701
|
-
| `/admin/settings/akismet` | `POST` only. Saves the Akismet key, or forgets it.
|
|
1702
|
-
| `/admin/settings/email` | The mail provider, the From line, the reply-to and the contact address.
|
|
1703
|
-
| `/admin/settings/mail` | `POST` only. Saves a mail credential, or forgets every one of them.
|
|
1704
|
-
| `/admin/settings/mail/test` | `POST` only. Sends the theme's test message through the whole chain.
|
|
1705
|
-
| `/admin/users` | Who may sign in: a row each, with Edit and Delete. Nothing on it edits anybody.
|
|
1706
|
-
| `/admin/users/new` | Users > Add new: the add form. `POST` adds one.
|
|
1707
|
-
| `/admin/users/<id>` | One user: the account, the profile, the notices, your password, and the delete.
|
|
1708
|
-
| `/admin/users/password` | `POST` only. Changes the signed-in admin's own password.
|
|
1709
|
-
| `/admin/users/email` | `POST` only. Sets or clears the email address on the user the form names.
|
|
1710
|
-
| `/admin/users/profile` | `POST` only. Saves the whole public profile of the user the form names.
|
|
1711
|
-
| `/admin/users/notifications` | `POST` only. Turns one notice on or off for the user the form names.
|
|
1712
|
-
| `/admin/users/notifications/mode` | `POST` only. Sets how often that notice arrives: as they arrive, hourly or daily.
|
|
1713
|
-
| `/admin/users/delete` | `POST` only. Deletes the user the form names.
|
|
1714
|
-
| `/admin/federation` | The actors, their followers, the inbox log, and per-post delivery.
|
|
1715
|
-
| `/admin/federation/settings` | Federation > Settings: the relays the site subscribes to, and the WordPress switch.
|
|
1716
|
-
| `/admin/federation/resend` | `POST` only. Sends one post to the followers again, as its file now reads.
|
|
1717
|
-
| `/admin/setup` | First run: creates the first admin. Closed once a user exists.
|
|
1718
|
-
| `/admin/login` | Username and password.
|
|
1719
|
-
| `/admin/logout` | `POST` only. Deletes the session row and sends `Clear-Site-Data`.
|
|
1720
|
-
| `/admin/_static/*` | The admin's own stylesheet and scripts, cached for an hour.
|
|
1781
|
+
| Route | What it does |
|
|
1782
|
+
| ------------------------------------------------ | --------------------------------------------------------------------------------------------- |
|
|
1783
|
+
| `/admin` | The dashboard: counts, the five most recent posts, the follower count. |
|
|
1784
|
+
| `/admin/posts`, `/admin/pages` | The listings and the editors. |
|
|
1785
|
+
| `/admin/tags`, `/admin/categories` | Every term in use, with rename, merge and delete. |
|
|
1786
|
+
| `/admin/tags/rename`, `/admin/categories/rename` | `POST` only. Renames a term, or merges it into one that exists. |
|
|
1787
|
+
| `/admin/tags/delete`, `/admin/categories/delete` | `POST` only. Takes a term out of every file. |
|
|
1788
|
+
| `/admin/navigation` | Navigation > Menus: every menu the site holds. `POST` saves one menu's items. |
|
|
1789
|
+
| `/admin/navigation/add` | `POST` only. Adds an empty menu under the name the form gives. |
|
|
1790
|
+
| `/admin/navigation/delete` | `POST` only. Deletes one menu the active theme renders nowhere. |
|
|
1791
|
+
| `/admin/media` | Everything under `content/uploads`, with the URL, the Markdown and what uses it. |
|
|
1792
|
+
| `/admin/media/upload` | `POST` only. Stores one file by the rules the editor's upload enforces. |
|
|
1793
|
+
| `/admin/media/delete` | `POST` only. Deletes one upload, asking first when a document points at it. |
|
|
1794
|
+
| `/admin/media/alt` | `POST` only. Sets a picture's alt text, or marks it decorative, in `media.json`. |
|
|
1795
|
+
| `/admin/comments` | Pending, approved and spam, with approve, spam, delete and reply. |
|
|
1796
|
+
| `/admin/comments/moderate` | `POST` only. Approves one comment, files it as spam, or deletes it. |
|
|
1797
|
+
| `/admin/comments/reply` | `POST` only. Posts an approved reply under the comment it answers. |
|
|
1798
|
+
| `/admin/messages` | The contact form's inbox, with a Spam list beside it. |
|
|
1799
|
+
| `/admin/messages/read` | `POST` only. Marks one message read, or unread again. |
|
|
1800
|
+
| `/admin/messages/delete` | `POST` only. Deletes one message, and its file with it. |
|
|
1801
|
+
| `/admin/appearance/themes` | Appearance > Themes: the themes on disk. `POST` activates the one named. |
|
|
1802
|
+
| `/admin/tools` | Tools > Content index: what the index holds, and the button that rebuilds it. |
|
|
1803
|
+
| `/admin/tools/rebuild-index` | `POST` only. Offers the rebuild, then reads every file again on the live site. |
|
|
1804
|
+
| `/admin/settings` | Settings > General: title, tagline, author, base URL, time zone, language, locale, site icon. |
|
|
1805
|
+
| `/admin/settings/reading` | What the homepage displays, posts per page, the notify server. |
|
|
1806
|
+
| `/admin/settings/permalinks` | The tag and category bases, and the archive redirects already recorded. |
|
|
1807
|
+
| `/admin/settings/discussion` | Comments and the closing window, webmentions, and the Akismet key. |
|
|
1808
|
+
| `/admin/settings/akismet` | `POST` only. Saves the Akismet key, or forgets it. |
|
|
1809
|
+
| `/admin/settings/email` | The mail provider, the From line, the reply-to and the contact address. |
|
|
1810
|
+
| `/admin/settings/mail` | `POST` only. Saves a mail credential, or forgets every one of them. |
|
|
1811
|
+
| `/admin/settings/mail/test` | `POST` only. Sends the theme's test message through the whole chain. |
|
|
1812
|
+
| `/admin/users` | Who may sign in: a row each, with Edit and Delete. Nothing on it edits anybody. |
|
|
1813
|
+
| `/admin/users/new` | Users > Add new: the add form. `POST` adds one. |
|
|
1814
|
+
| `/admin/users/<id>` | One user: the account, the profile, the notices, your password, and the delete. |
|
|
1815
|
+
| `/admin/users/password` | `POST` only. Changes the signed-in admin's own password. |
|
|
1816
|
+
| `/admin/users/email` | `POST` only. Sets or clears the email address on the user the form names. |
|
|
1817
|
+
| `/admin/users/profile` | `POST` only. Saves the whole public profile of the user the form names. |
|
|
1818
|
+
| `/admin/users/notifications` | `POST` only. Turns one notice on or off for the user the form names. |
|
|
1819
|
+
| `/admin/users/notifications/mode` | `POST` only. Sets how often that notice arrives: as they arrive, hourly or daily. |
|
|
1820
|
+
| `/admin/users/delete` | `POST` only. Deletes the user the form names. |
|
|
1821
|
+
| `/admin/federation` | The actors, their followers, the inbox log, and per-post delivery. |
|
|
1822
|
+
| `/admin/federation/settings` | Federation > Settings: the relays the site subscribes to, and the WordPress switch. |
|
|
1823
|
+
| `/admin/federation/resend` | `POST` only. Sends one post to the followers again, as its file now reads. |
|
|
1824
|
+
| `/admin/setup` | First run: creates the first admin. Closed once a user exists. |
|
|
1825
|
+
| `/admin/login` | Username and password. |
|
|
1826
|
+
| `/admin/logout` | `POST` only. Deletes the session row and sends `Clear-Site-Data`. |
|
|
1827
|
+
| `/admin/_static/*` | The admin's own stylesheet and scripts, cached for an hour. |
|
|
1721
1828
|
|
|
1722
1829
|
The screens behind the login share one layout: a bar across the top with the
|
|
1723
1830
|
site name and a link to the public site, the menu down the left, and a place for
|
|
@@ -1846,7 +1953,8 @@ at once cannot each keep half of what the other kept.
|
|
|
1846
1953
|
|
|
1847
1954
|
The file carries `title`, `tagline`, `url`, `author` (a username, when the
|
|
1848
1955
|
site has one author), `postsPerPage`, `homepage`, `postsPage`,
|
|
1849
|
-
`timezone`, `language`, `locale` (when it is set), `
|
|
1956
|
+
`timezone`, `language`, `locale` (when it is set), `icon` (when it is set),
|
|
1957
|
+
`license` and `licenseName` (when a license is chosen; see below), `tagBase`,
|
|
1850
1958
|
`categoryBase`, `notifyServer`, `feedUpdatePeriod`, `feedUpdateFrequency`,
|
|
1851
1959
|
`webmentionsSend`, `webmentionsReceive`,
|
|
1852
1960
|
`mailProvider`, `mailFromName`, `mailFromAddress`, `mailReplyTo`,
|
|
@@ -1999,7 +2107,7 @@ would have done anyway.
|
|
|
1999
2107
|
| `removeImageVariants` | Take a source's derived directory away. |
|
|
2000
2108
|
| `responsiveImages(html, describe)` | Rewrite `<img src="/uploads/…">` as `<picture>`. Pure: hand it any lookup. |
|
|
2001
2109
|
| `siteImageMarkup(config, html)` | The same, over one site's own records, deriving in the background for a record miss. |
|
|
2002
|
-
| `siteIcons(config,
|
|
2110
|
+
| `siteIcons(config, setting)` | The head's icon links for a site's icon setting: `{ rel, sizes, href }`, or none. |
|
|
2003
2111
|
|
|
2004
2112
|
`describeImage` is synchronous and cached because it is called once per image
|
|
2005
2113
|
while a page renders, and decision-10 forbids probing an image file at render
|
|
@@ -2009,10 +2117,11 @@ markup that asks for them back, and the first request for each one rebuilds it.
|
|
|
2009
2117
|
|
|
2010
2118
|
The site's icons are derived copies of the same kind, and `siteIcons` is how a
|
|
2011
2119
|
head gets at them: three square PNGs, `icon` at 32 and 16 pixels and
|
|
2012
|
-
`apple-touch-icon` at 180, cropped from the middle of the site's
|
|
2120
|
+
`apple-touch-icon` at 180, cropped from the middle of the site's icon (the
|
|
2121
|
+
`icon` that Settings > General writes, else a hand-set `avatar`) and
|
|
2013
2122
|
encoded the first time a browser asks for one. It answers an empty list — and
|
|
2014
|
-
the packaged theme then links no icon at all — when the site has no
|
|
2015
|
-
its
|
|
2123
|
+
the packaged theme then links no icon at all — when the site has no icon, when
|
|
2124
|
+
its icon is a file no icon can be made of, or when `imageOptimization` is off,
|
|
2016
2125
|
so a head never advertises a URL this server would answer 404 for.
|
|
2017
2126
|
|
|
2018
2127
|
`documentContext(document, images)` is where the rewrite is applied. Passing the
|
|
@@ -2869,8 +2978,22 @@ to read them on, `wfw:commentRss` (the [Well-Formed Web][wfw-ns] comment API) is
|
|
|
2869
2978
|
the feed to poll, and `source:comments` is that same feed with a `count`
|
|
2870
2979
|
attribute, so a reader can say "3 comments" without fetching anything.
|
|
2871
2980
|
|
|
2981
|
+
When the site has a license (Settings > General, or `license` in `site.json`),
|
|
2982
|
+
the channel carries a `creativeCommons:license` holding its URL, and every item
|
|
2983
|
+
carries one for its own license: the post's `license` front matter, else the
|
|
2984
|
+
site's. A post whose front matter says `license: none` carries none. The
|
|
2985
|
+
element is the [Creative Commons RSS module][cc-rss], declared as
|
|
2986
|
+
`xmlns:creativeCommons` only when some license is printed. It names a license
|
|
2987
|
+
by URL, Creative Commons or not, which a reader can act on; `dc:rights` would be
|
|
2988
|
+
free text. Nothing about a license is printed on a site and posts without one.
|
|
2989
|
+
RSS has no element that says "no license", so a post saying `license: none`
|
|
2990
|
+
on a licensed site carries no item license while the channel still names the
|
|
2991
|
+
site's; a reader that applies the channel's license to every item reads that
|
|
2992
|
+
post as under it.
|
|
2993
|
+
|
|
2872
2994
|
[source-ns]: https://source.scripting.com/
|
|
2873
2995
|
[wfw-ns]: http://wellformedweb.org/CommentAPI/
|
|
2996
|
+
[cc-rss]: https://cyber.harvard.edu/rss/creativeCommonsRssModule.html
|
|
2874
2997
|
|
|
2875
2998
|
### Comments
|
|
2876
2999
|
|
|
@@ -2925,6 +3048,14 @@ post as `content type="html"`. The feed itself carries `id`, `title`,
|
|
|
2925
3048
|
`xml:lang` from the `language` setting, and — when the site names a notify
|
|
2926
3049
|
server — a `source:cloud` and a `link rel="hub"`.
|
|
2927
3050
|
|
|
3051
|
+
With a license, the feed carries an [RFC 4946][rfc4946] `link rel="license"`
|
|
3052
|
+
to the site's license, its name as the `title`, and every entry carries one for
|
|
3053
|
+
its own license, the post's `license` front matter else the site's. An entry
|
|
3054
|
+
states its own because RFC 4946 does not let an entry inherit the feed's. JSON
|
|
3055
|
+
Feed has no field for a license and says nothing about one.
|
|
3056
|
+
|
|
3057
|
+
[rfc4946]: https://www.rfc-editor.org/rfc/rfc4946
|
|
3058
|
+
|
|
2928
3059
|
A JSON Feed item carries `id` (the object id), `url` (the permalink), `title`,
|
|
2929
3060
|
`content_html`, `summary`, `date_published`, `date_modified`, `tags` (the
|
|
2930
3061
|
terms) and `authors`; the feed carries `version`, `title`, `home_page_url`,
|
|
@@ -2935,6 +3066,93 @@ The XML is written by this package rather than by a library. Text is escaped;
|
|
|
2935
3066
|
`content:encoded` and `source:markdown` are CDATA sections, with any `]]>` in
|
|
2936
3067
|
the text split across two sections so it cannot end one early.
|
|
2937
3068
|
|
|
3069
|
+
### A recording on a post
|
|
3070
|
+
|
|
3071
|
+
A post can carry one recording: a spoken version of an article, or an episode
|
|
3072
|
+
now and then. The site is a blog that sometimes has audio, not a podcast host,
|
|
3073
|
+
so the feeds carry what a podcast app needs to play, describe and caption an
|
|
3074
|
+
item, and leave the podcast directory tags out. The front matter spells it the
|
|
3075
|
+
way RSS does:
|
|
3076
|
+
|
|
3077
|
+
```yaml
|
|
3078
|
+
enclosure:
|
|
3079
|
+
url: /uploads/2026/10/episode-12.mp3 # an upload; written by the editor
|
|
3080
|
+
type: audio/mpeg # from the upload table; written by the editor
|
|
3081
|
+
length: 23456789 # bytes, from the file on disk; written by the editor
|
|
3082
|
+
duration: 1834 # seconds, optional
|
|
3083
|
+
transcript: # optional
|
|
3084
|
+
url: /uploads/2026/10/episode-12.vtt # an upload or an http(s) URL
|
|
3085
|
+
type: text/vtt # text/vtt, application/x-subrip, text/html or text/plain
|
|
3086
|
+
alternates: # optional, any number
|
|
3087
|
+
- url: /uploads/2026/10/episode-12.mp4
|
|
3088
|
+
type: video/mp4
|
|
3089
|
+
length: 98765432
|
|
3090
|
+
title: Video # optional, at most 32 characters
|
|
3091
|
+
height: 720 # optional, for video
|
|
3092
|
+
lang: en # optional
|
|
3093
|
+
- url: https://cdn.example.com/episode-12-low.mp3
|
|
3094
|
+
type: audio/mpeg # required for a link
|
|
3095
|
+
title: Low bandwidth # a link's length is optional
|
|
3096
|
+
```
|
|
3097
|
+
|
|
3098
|
+
**The main file is always an upload** under `/uploads/`, because RSS requires
|
|
3099
|
+
its `url`, `length` and `type`, and an upload is the only file whose length the
|
|
3100
|
+
site knows. A main file without all three is no recording at all. A bad
|
|
3101
|
+
alternate version or transcript is dropped on its own, so one wrong line in a
|
|
3102
|
+
hand-edited file costs that line and not the episode. `enclosureOf(extra)` is
|
|
3103
|
+
the one reading of the key, and the feeds, the theme and the federation read
|
|
3104
|
+
only what it returns.
|
|
3105
|
+
|
|
3106
|
+
**The post editor** has a Recording section on posts. The main file is a select
|
|
3107
|
+
of the audio and video in the media library, and None removes the whole key,
|
|
3108
|
+
transcript and alternate versions included. The duration takes seconds, `30:34`
|
|
3109
|
+
or `1:02:03`. The transcript is an upload (`.vtt`, `.srt` or `.txt`) or an
|
|
3110
|
+
`https` address with its type. Alternate versions are numbered rows with one
|
|
3111
|
+
blank row at the end, so a plain form can add, edit and remove them; emptying a
|
|
3112
|
+
row's address removes it. On save, the type and length of every upload are read
|
|
3113
|
+
from the upload table and from the file on disk, never from the form. A main
|
|
3114
|
+
file that is not an audio or video upload, a linked version without an `http`
|
|
3115
|
+
or `https` address or a media type, or a title over 32 characters is refused
|
|
3116
|
+
with a message, and nothing is written.
|
|
3117
|
+
|
|
3118
|
+
**What the feeds print, and when.** A post with no recording prints none of
|
|
3119
|
+
this, and a feed with no recording in it declares neither namespace, so its
|
|
3120
|
+
bytes and its ETag are what they were before recordings existed.
|
|
3121
|
+
|
|
3122
|
+
| Element | Format | Printed when |
|
|
3123
|
+
| ----------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
3124
|
+
| `<enclosure url length type/>` | RSS item | The post has a main file. `url` is absolute. |
|
|
3125
|
+
| `<podcast:alternateEnclosure>` with `<podcast:source uri/>` | RSS item | Once per alternate version, with `type`, and `length`, `title`, `height` and `lang` when known. |
|
|
3126
|
+
| `<podcast:transcript url type/>` | RSS item | The post has a transcript, with `rel="captions"` for WebVTT or SubRip. |
|
|
3127
|
+
| `<itunes:duration>` | RSS item | The duration is known, in whole seconds. |
|
|
3128
|
+
| `<podcast:medium>blog</podcast:medium>` | RSS channel | Any item in the feed has a recording. Without it an app assumes `podcast`; `blog` is the spec's word for articles that sometimes have audio. |
|
|
3129
|
+
| `<link rel="enclosure" type length href/>` | Atom entry | The post has a main file. Atom has no way to say the others are versions of it. |
|
|
3130
|
+
| `attachments` | JSON Feed | The main file and then each alternate version, with `url`, `mime_type`, `size_in_bytes` and `title` when known, and `duration_in_seconds` on audio or video when the duration is known. |
|
|
3131
|
+
|
|
3132
|
+
`xmlns:podcast="https://podcastindex.org/namespace/1.0"` is declared only on a
|
|
3133
|
+
feed that prints a podcast element, and
|
|
3134
|
+
`xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"` only on one that
|
|
3135
|
+
prints `itunes:duration`.
|
|
3136
|
+
|
|
3137
|
+
**Left out on purpose:** the Apple directory tags (`itunes:image`,
|
|
3138
|
+
`itunes:category`, `itunes:explicit`, `itunes:owner`), and `podcast:guid`,
|
|
3139
|
+
`podcast:locked`, `podcast:person`, `podcast:season`, `podcast:episode`,
|
|
3140
|
+
`podcast:value` and `podcast:chapters`. Each one matters only to a podcast
|
|
3141
|
+
directory or a dedicated show. Adding them is a follow-up for a site that wants
|
|
3142
|
+
to be listed in Apple Podcasts, and so is `podcast:license`, which could reuse
|
|
3143
|
+
the [content license](#rss-20).
|
|
3144
|
+
|
|
3145
|
+
**The fediverse** gets the main file as an `Audio` or `Video` attachment with
|
|
3146
|
+
its absolute `url`, its `mediaType`, and the post's title, or a note's first
|
|
3147
|
+
words, as its `name`. It goes before the post's `Image` attachments, because
|
|
3148
|
+
Mastodon shows a player or a gallery by the type of the first attachment and
|
|
3149
|
+
keeps only four. Alternate versions and linked files stay out: a remote server
|
|
3150
|
+
fetches and re-encodes what it is given, and a link to another host is a type
|
|
3151
|
+
this site cannot check. `playsAsVideo(type)` decides `Video` against `Audio`,
|
|
3152
|
+
and the default theme's `<video>` against `<audio>`, so the two never disagree.
|
|
3153
|
+
|
|
3154
|
+
The default theme plays the main file on the post page; see its README.
|
|
3155
|
+
|
|
2938
3156
|
### Real-time notification
|
|
2939
3157
|
|
|
2940
3158
|
A feed reader that polls hears about a post when it next polls. An [rssCloud][]
|
|
@@ -62,6 +62,97 @@
|
|
|
62
62
|
formnovalidate
|
|
63
63
|
>Preview</button>
|
|
64
64
|
</div>
|
|
65
|
+
|
|
66
|
+
{% if kind.type == "post" %}
|
|
67
|
+
<fieldset class="admin-editor-enclosure admin-editor-photos">
|
|
68
|
+
<legend>Photos</legend>
|
|
69
|
+
<p class="admin-hint">
|
|
70
|
+
Each is an image in the media library or an address starting https://. Leave the alt text
|
|
71
|
+
empty to use the media library’s. Empty an address to remove that photo.
|
|
72
|
+
</p>
|
|
73
|
+
{% for row in photoRows %}
|
|
74
|
+
{% set n = loop.index0 %}
|
|
75
|
+
<fieldset class="admin-editor-alternate">
|
|
76
|
+
<legend>{% if row.url %}Photo {{ loop.index }}{% else %}Add a photo{% endif %}</legend>
|
|
77
|
+
<label for="editor-photo-url-{{ n }}">Address</label>
|
|
78
|
+
<input id="editor-photo-url-{{ n }}" name="{{ photoFields.url }}{{ n }}" type="text" value="{{ row.url }}" list="editor-photo-uploads" autocomplete="off" />
|
|
79
|
+
<label for="editor-photo-alt-{{ n }}">Alt text</label>
|
|
80
|
+
<input id="editor-photo-alt-{{ n }}" name="{{ photoFields.alt }}{{ n }}" type="text" value="{{ row.alt }}"{% if row.libraryAlt %} placeholder="{{ row.libraryAlt }}"{% endif %} />
|
|
81
|
+
</fieldset>
|
|
82
|
+
{% endfor %}
|
|
83
|
+
<datalist id="editor-photo-uploads">
|
|
84
|
+
{% for url in photoChoices %}
|
|
85
|
+
<option value="{{ url }}"></option>
|
|
86
|
+
{% endfor %}
|
|
87
|
+
</datalist>
|
|
88
|
+
</fieldset>
|
|
89
|
+
<fieldset class="admin-editor-enclosure">
|
|
90
|
+
<legend>Recording</legend>
|
|
91
|
+
|
|
92
|
+
<label for="editor-enclosure-url">Audio or video file</label>
|
|
93
|
+
<select id="editor-enclosure-url" name="{{ enclosureFields.url }}" aria-describedby="editor-enclosure-url-hint">
|
|
94
|
+
<option value=""{% if form.enclosure.url == "" %} selected{% endif %}>None</option>
|
|
95
|
+
{% for choice in enclosureChoices.media %}
|
|
96
|
+
<option value="{{ choice.url }}"{% if choice.url == form.enclosure.url %} selected{% endif %}>{{ choice.label }}</option>
|
|
97
|
+
{% endfor %}
|
|
98
|
+
</select>
|
|
99
|
+
<p class="admin-hint" id="editor-enclosure-url-hint">
|
|
100
|
+
Upload the file to the media library first. Feeds carry it as the post’s enclosure and the
|
|
101
|
+
post page plays it. None removes the recording, its transcript and its other versions.
|
|
102
|
+
</p>
|
|
103
|
+
|
|
104
|
+
<label for="editor-enclosure-duration">Duration</label>
|
|
105
|
+
<input id="editor-enclosure-duration" name="{{ enclosureFields.duration }}" type="text" inputmode="numeric" value="{{ form.enclosure.duration }}" autocomplete="off" aria-describedby="editor-enclosure-duration-hint" />
|
|
106
|
+
<p class="admin-hint" id="editor-enclosure-duration-hint">Seconds, or 30:34, or 1:02:03. Leave it empty if you do not know.</p>
|
|
107
|
+
|
|
108
|
+
<label for="editor-enclosure-transcript">Transcript or captions</label>
|
|
109
|
+
<input id="editor-enclosure-transcript" name="{{ enclosureFields.transcriptUrl }}" type="text" value="{{ form.enclosure.transcriptUrl }}" list="editor-transcript-uploads" autocomplete="off" aria-describedby="editor-enclosure-transcript-hint" />
|
|
110
|
+
<datalist id="editor-transcript-uploads">
|
|
111
|
+
{% for url in enclosureChoices.transcripts %}
|
|
112
|
+
<option value="{{ url }}"></option>
|
|
113
|
+
{% endfor %}
|
|
114
|
+
</datalist>
|
|
115
|
+
<label for="editor-enclosure-transcript-type">Transcript type</label>
|
|
116
|
+
<select id="editor-enclosure-transcript-type" name="{{ enclosureFields.transcriptType }}" aria-describedby="editor-enclosure-transcript-hint">
|
|
117
|
+
<option value=""{% if form.enclosure.transcriptType == "" %} selected{% endif %}>From the file</option>
|
|
118
|
+
{% for type in transcriptTypes %}
|
|
119
|
+
<option value="{{ type }}"{% if type == form.enclosure.transcriptType %} selected{% endif %}>{{ type }}</option>
|
|
120
|
+
{% endfor %}
|
|
121
|
+
</select>
|
|
122
|
+
<p class="admin-hint" id="editor-enclosure-transcript-hint">
|
|
123
|
+
A .vtt, .srt or .txt file in the media library, or an address starting https://. A linked
|
|
124
|
+
transcript needs its type.
|
|
125
|
+
</p>
|
|
126
|
+
|
|
127
|
+
<h2 class="admin-editor-enclosure-heading">Other versions</h2>
|
|
128
|
+
<p class="admin-hint">
|
|
129
|
+
A video of an audio episode, a smaller file, another language. Each is a file in the media
|
|
130
|
+
library or an address starting https://, which needs its type. Empty an address to remove
|
|
131
|
+
that version.
|
|
132
|
+
</p>
|
|
133
|
+
{% for row in alternateRows %}
|
|
134
|
+
{% set n = loop.index0 %}
|
|
135
|
+
<fieldset class="admin-editor-alternate">
|
|
136
|
+
<legend>{% if row.url %}Version {{ loop.index }}{% else %}Add a version{% endif %}</legend>
|
|
137
|
+
<label for="editor-alternate-url-{{ n }}">Address</label>
|
|
138
|
+
<input id="editor-alternate-url-{{ n }}" name="{{ enclosureFields.alternate.url }}{{ n }}" type="text" value="{{ row.url }}" list="editor-media-uploads" autocomplete="off" />
|
|
139
|
+
<label for="editor-alternate-type-{{ n }}">Type</label>
|
|
140
|
+
<input id="editor-alternate-type-{{ n }}" name="{{ enclosureFields.alternate.type }}{{ n }}" type="text" value="{{ row.type }}" placeholder="video/mp4" autocomplete="off" spellcheck="false" />
|
|
141
|
+
<label for="editor-alternate-title-{{ n }}">Title</label>
|
|
142
|
+
<input id="editor-alternate-title-{{ n }}" name="{{ enclosureFields.alternate.title }}{{ n }}" type="text" value="{{ row.title }}" maxlength="32" />
|
|
143
|
+
<label for="editor-alternate-height-{{ n }}">Height</label>
|
|
144
|
+
<input id="editor-alternate-height-{{ n }}" name="{{ enclosureFields.alternate.height }}{{ n }}" type="text" inputmode="numeric" value="{{ row.height }}" autocomplete="off" />
|
|
145
|
+
<label for="editor-alternate-lang-{{ n }}">Language</label>
|
|
146
|
+
<input id="editor-alternate-lang-{{ n }}" name="{{ enclosureFields.alternate.lang }}{{ n }}" type="text" value="{{ row.lang }}" autocomplete="off" spellcheck="false" />
|
|
147
|
+
</fieldset>
|
|
148
|
+
{% endfor %}
|
|
149
|
+
<datalist id="editor-media-uploads">
|
|
150
|
+
{% for choice in enclosureChoices.media %}
|
|
151
|
+
<option value="{{ choice.url }}"></option>
|
|
152
|
+
{% endfor %}
|
|
153
|
+
</datalist>
|
|
154
|
+
</fieldset>
|
|
155
|
+
{% endif %}
|
|
65
156
|
</div>
|
|
66
157
|
|
|
67
158
|
<div class="admin-editor-side">
|
|
@@ -98,6 +189,16 @@
|
|
|
98
189
|
<label for="editor-in-reply-to">In reply to</label>
|
|
99
190
|
<input id="editor-in-reply-to" name="in-reply-to" type="url" value="{{ form.inReplyTo }}" />
|
|
100
191
|
<p class="admin-hint">The address of the post this one answers. Leave it empty for a post that answers nobody.</p>
|
|
192
|
+
|
|
193
|
+
{#- The mf2 `like-of`, `repost-of` and `bookmark-of` (TASK-169): each
|
|
194
|
+
cites a page the way a reply does, and sends it a webmention. -#}
|
|
195
|
+
<label for="editor-like-of">Like of</label>
|
|
196
|
+
<input id="editor-like-of" name="like-of" type="url" value="{{ form.likeOf }}" />
|
|
197
|
+
<label for="editor-repost-of">Repost of</label>
|
|
198
|
+
<input id="editor-repost-of" name="repost-of" type="url" value="{{ form.repostOf }}" />
|
|
199
|
+
<label for="editor-bookmark-of">Bookmark of</label>
|
|
200
|
+
<input id="editor-bookmark-of" name="bookmark-of" type="url" value="{{ form.bookmarkOf }}" />
|
|
201
|
+
<p class="admin-hint">The address of a post this one likes, reposts or bookmarks. Leave them empty for a post that cites nothing.</p>
|
|
101
202
|
{% endif %}
|
|
102
203
|
|
|
103
204
|
<label for="editor-description">Description</label>
|
|
@@ -141,6 +242,25 @@
|
|
|
141
242
|
</p>
|
|
142
243
|
{% endif %}
|
|
143
244
|
|
|
245
|
+
{% if kind.type == "post" and syndicationTargets.length %}
|
|
246
|
+
{# TASK-155: the targets content/_data/syndicationTargets.json declares.
|
|
247
|
+
A target whose tag the post carries is selected without a tick. #}
|
|
248
|
+
<fieldset class="admin-editor-syndication">
|
|
249
|
+
<legend>Syndicate to</legend>
|
|
250
|
+
{% for target in syndicationTargets %}
|
|
251
|
+
<p class="admin-check">
|
|
252
|
+
<input id="editor-{{ target.field }}" name="{{ target.field }}" type="checkbox" value="1"{% if target.checked %} checked{% endif %} />
|
|
253
|
+
<label for="editor-{{ target.field }}">{{ target.name }}</label>
|
|
254
|
+
</p>
|
|
255
|
+
{% endfor %}
|
|
256
|
+
<p class="admin-hint">
|
|
257
|
+
Writes <code>syndicate-to:</code> into the front matter. The post links to each target and
|
|
258
|
+
sends it a webmention when it is published or updated. A post tagged with a target’s tag is
|
|
259
|
+
sent there without a tick.
|
|
260
|
+
</p>
|
|
261
|
+
</fieldset>
|
|
262
|
+
{% endif %}
|
|
263
|
+
|
|
144
264
|
{# What this document says about comments, if anything. Three answers
|
|
145
265
|
rather than two: the site's own rules, always open, always closed. #}
|
|
146
266
|
<label for="editor-comments">Comments</label>
|