Canvas¶
frontend_editing_canvas lets editors edit the components of a Drupal Canvas
page from the front end. Hover a component, click Edit, and its form opens in the usual
Frontend Editing sidebar.
drush en frontend_editing_canvas
Dependencies: frontend_editing, canvas (1.12 or later). Drupal 11.3 or later.
What it does¶
- Outlines the hovered component and shows a bar with its name and an Edit button. The outline and the bar look the same as for paragraphs: same colors (including the configured primary color), same bar, same pencil icon. Components around the hovered one get a lighter outline and no bar.
- Opens the component's form in the sidebar, in the admin theme. The sidebar can be resized and detached like for any other entity.
- Keeps every change as an unpublished change (the Canvas draft of the page) and refreshes the page content in place, without a full reload. A badge next to the editing toggle counts the changed components. Its panel lists them and publishes or discards all of them at once, as one new revision. With the save mode "direct", every change is a new revision at once.
- Lets editors move a component up and down among its siblings, delete it (after a confirmation), duplicate it and add components: with the plus buttons on the top and bottom edge (before and after), and with the plus button in the bar of a component that has slots (into a slot). All of these look and behave like the same actions on paragraphs.
- Works for components from single directory components, code components and block plugins.
- Follows the editing mode toggle: hidden components and links when editing is switched off.
The form uses the same field widgets as the Canvas editor, so the same values end up in the page. Nested components (in slots) are supported; hovering picks the innermost component under the pointer.
Limitations¶
- Only
canvas_pageentities. In Canvas 1.12 other entity types, such as nodes, get their components from content templates, which are configuration and not edited from the front end. - In the save mode "draft" (the default) editors see and change the draft of the page. It is shared with every other editor and with the Canvas editor: there is no draft per user.
- In the save mode "direct", every action is its own revision, and a component deleted by mistake is only recoverable from the page's revisions. If the page has a Canvas draft, the form warns that saving creates a revision that conflicts with it.
- The color picker is a plain color field: no transparency and no Brand Kit colors. Use the Open in Admin UI button in the sidebar header to open the component in Canvas instead.
- Adding stores the new component with its default values first, then its edit form opens. Closing the sidebar at that point keeps the component with those default values (in the draft, until it is discarded).
- The badge and panel are floating, next to the editing toggle. The toolbar variants of the paragraphs save queue are not available.
- Dragging components and adding into the empty page are not available.
Configuration¶
Installing the module enables the canvas_page entity type in
Entity types and bundles. Canvas pages have no bundles, so the Page
tab of that form lists the components instead:
| Setting | Effect |
|---|---|
| Which components can be changed? | All except those selected (the default, with nothing selected: all components) or Only those selected. The components are listed per source: single directory components, code components and blocks. It applies to editing, moving, deleting, duplicating and adding. |
The Canvas section of the Frontend Editing settings form (/admin/config/frontend-editing)
adds this setting:
| Setting | Effect |
|---|---|
| Saving changes | Draft (the default): changes wait as unpublished changes of the page, and are published together. Direct: every change is a new revision at once. |
Components without any props get no Edit button, but can still be moved, deleted, duplicated and added. Broken components never get any action.
Editors need the access frontend editing permission and the permission to edit the Canvas page
(edit canvas_page). The other actions use the same permissions as the items of entity reference
fields, so they are managed in one place:
| Action | Permission |
|---|---|
| Edit | none besides the two above |
| Move up and down | frontend editing move items |
| Delete | frontend editing delete items |
| Duplicate | frontend editing duplicate items |
| Add | frontend editing add items |
| Publish the unpublished changes | publish auto-saves (a Canvas permission) |
Editing the page and discarding the unpublished changes need no more than the first two. An editor
without publish auto-saves sees the changes and the panel, but somebody else has to publish them.
The choice of components applies to all of these actions: a component that is not allowed cannot be edited, moved, deleted, duplicated or added.
How it works¶
Canvas does not mark its components on the live page, so the module adds two HTML comments around
each component instance (<!-- fe-canvas:start UUID --> and <!-- fe-canvas:end UUID -->) and one
pair around the whole page. They are added only for users with access frontend editing, and
never in Canvas's own editor preview. A script pairs the comments to find each component's area on
the page.
The edit form is built by Canvas itself. Canvas converts the submitted widget values into component
inputs in the browser, so this module does the same on the server
(Drupal\frontend_editing_canvas\ComponentInputExtractor). That class is the only place that
depends on Canvas internals, which Canvas does not yet offer as a stable API.
After a save, the sidebar sends the usual closeSidePanel message. The module answers it by
fetching the page again and replacing the content between the page-level comments. The same
happens after move, delete and duplicate, which are POST requests with a CSRF token that return
JSON, and after a component was added, when the sidebar asks the page to refresh.
Unpublished changes. With the save mode "draft", the front end reads and changes the Canvas
auto-save draft of the page (Drupal\frontend_editing_canvas\WorkingCopy returns the draft when
there is one, else the page). While a draft exists, editors see it on the page instead of the stored
page, and everybody else sees the stored page. Publishing calls Canvas's own publish for the page,
after putting the revision log message, the author and the time on the draft, so that Canvas stores
one new revision with all the changes. The list in the panel (added, edited, moved, removed) comes
from comparing the draft with the stored page. When the stored page changed after the draft was
started, publishing would replace those changes: the panel then says so, Publish is disabled and
the server refuses the request (409) without touching the draft. Discard all is the way out, the
changes of the draft have to be made again on the current page.
The tree is changed by Drupal\frontend_editing_canvas\ComponentTreeEditor. It works on the raw
values of the component_tree field and writes every item after its parent, which keeps Canvas's
rules for the tree (parents exist, the order of siblings is their order in the field) true. Moving
swaps places with the nearest sibling in the same slot, and takes the children along. Duplicating
copies the whole subtree with new UUIDs. Deleting removes the subtree.
Tests¶
tests/src/Kernel/: access, markers, input extraction, the tree editor, the add form and the draft mode.tests/src/FunctionalJavascript/: browser tests in Chrome through WebDriver.DirectModeTestcovers the hover bar, permissions, editing in the sidebar, move, duplicate, delete (with the confirmation) and add.DraftModeTestcovers collecting changes in the draft, publishing them as one revision with a log message, discarding, and the missing publish permission.