feat(16.2-01): translatable plugin fields, element uploads and save notices in the admin
- MLPluginField wraps PluginField in the MLField locale switcher; the
element gets the active content locale and that locale's string
- isMLField treats a translatable plugin field as a locale map in the form
state, FormView adopt and the relation child modal
- summer-upload posts the file with the admin session to the field upload
route and answers summer-upload-result {id, url} or {id, error}
- noticeLines shows meta.notices under each field as a warning status line
(text only) and in the saved toast; the stored value is reloaded
- docs/backend/field-types.md documents the full element contract;
modules/boardwalk/dist rebuilt
This commit is contained in:
@@ -122,11 +122,19 @@ A type that stores files (images in a document, say) sets `Upload`. The element
|
||||
|
||||
## The element
|
||||
|
||||
The admin creates the type's element for the field and talks to it through one property, attributes and events, nothing else:
|
||||
The admin creates the type's element for the field and talks to it through one property, attributes and events, nothing else. The element contract:
|
||||
|
||||
- The `value` property holds the field's value: any JSON value for a type that is not translatable.
|
||||
- The attributes `field-name`, `record-id` (empty on the create form), `locale` (empty for a type that is not translatable), `ui-locale` (the admin's interface language), `options` (the JSON of `typeOptions`), `disabled` (present when the field is read-only) and `invalid` (present while the field has an error).
|
||||
- The element dispatches a bubbling `summer-change` event with `detail.value` when the administrator edits the value, and only then; the admin takes `detail.value` as the field's new value.
|
||||
- The admin sets `value` only when the form value differs from the element's current `value`, so setting the value the element just emitted never resets it. An element must still accept a `value` it did not emit, such as the stored value after a save.
|
||||
- The `value` property holds the field's value: a string (the active locale's text) for a translatable type, any JSON value otherwise.
|
||||
- The attributes are `field-name`; `record-id`, empty on the create form; `locale`, the content locale of the value for a translatable type and empty otherwise; `ui-locale`, the admin's interface language; `options`, the JSON of the field's `typeOptions`; `disabled`, present when the field is read-only (on a preview screen, for example); and `invalid`, present while the field has an error.
|
||||
- `summer-change` is a bubbling `CustomEvent` the element dispatches when the administrator edits the value, and only then. The admin takes `detail.value` as the field's new value; for a translatable type it replaces only the active locale's string in the locale map.
|
||||
- `summer-upload` is a bubbling `CustomEvent` the element dispatches to upload a file, with `detail` `{id, file}`: an id of the element's choosing and the `File`. The admin posts the file with the administrator's session to the field's [upload route](#uploads) and answers by dispatching `summer-upload-result` on the element, with `detail` `{id, url}` on success or `{id, error}` with a message to show (the server's message for a refused file, a generic one for a file that is too large or a network failure).
|
||||
- The admin sets `value` only when the form value differs from the element's current `value` (compared by JSON for objects), so setting the value the element just emitted never resets it. The element must still accept a `value` it did not emit: the stored value after a save, which may differ from what it emitted when `Decode` changed it, and the other locale's text when the administrator switches locales (the admin sets `locale` first, then `value`).
|
||||
- An element should not re-serialize a value the administrator did not edit, so an untouched value stays equal to the one it was served and the save skips it.
|
||||
|
||||
The element never receives a token, a cookie, a function or a Vue instance, and it makes no requests of its own. It styles itself only through the admin's public `--c-*` CSS variables, with every selector scoped under its own tag, because its stylesheet is enabled on every admin page.
|
||||
The element never receives a token, a cookie, a function or a Vue instance, and it makes no requests of its own: the admin owns HTTP and the session. It styles itself only through the admin's public `--c-*` CSS variables (`--c-bg`, `--c-surface`, `--c-text`, `--c-primary` and the others the cabana README lists, which switch with dark mode), with every selector scoped under its own tag, because its stylesheet is enabled on every admin page. A type whose script fails to load, or whose tag is not defined within five seconds, shows the admin's failure box in place of the field.
|
||||
|
||||
A translatable type renders inside the admin's locale switcher, the same one `mlmarkdown` uses: one element edits the active locale, and switching locales changes its `locale` attribute and its `value`.
|
||||
|
||||
### How the admin shows notices
|
||||
|
||||
After a save whose response carries `meta.notices`, the admin shows each message under its field as a warning status line, prefixed with the upper-case locale for a translatable type (`PL: 2 elements were removed: style, iframe`), and appends the messages to the saved toast, so "Save and close", which leaves the form, still tells the administrator. The lines go away on the next save attempt. The admin then reloads the stored values from the response into the form, and the element receives the stored value.
|
||||
|
||||
Reference in New Issue
Block a user