Skip to content

Canvas extensions cannot move the selection, which blocks structural authoring plugins #1281

Description

@keepthebyte

Summary

A canvas panel extension can read the document and insert into it, but it has no way to move the selection to a known place in the document. That one gap blocks a class of "manage the structure of this page" plugins, and it is the only thing standing between the current extension API and a working authoring tool we have prototyped.

Context

We are prototyping author tooling for section-scoped personalization on a customer site: sections carry an audience via section metadata (Style: audience-member, audience-silver), and each targeted section carries a generated note. Authoring this by hand is error-prone — the audience list is an unvalidated string, and a typo silently shows the section to everyone.

We built the tooling as a BYO panel extension, deliberately, to avoid asking for core changes. That works well for two of three jobs:

  • Read — the handshake in setupIframeChannel provides { org, repo, ref, path } plus the IMS token, so the plugin fetches the page source from admin.da.live and reports what each section targets. This is more capable than we first assumed and worth calling out in the docs.
  • InsertsendHTML reaches insertHTML, which does replaceRange(from, to, …), so a plugin can insert correctly-formed content through the editor and stay collab-safe.
  • Locate / edit an existing section — not possible.

The gap

channel.port1.onmessage in blocks/canvas/ew-panel-extensions/iframe-protocol.js handles sendText, sendHTML, setHash, setHref, closeLibrary, showPanel, setPrompt and getSelection. None of these can position the selection, and the canvas hash carries no node anchor. So a plugin cannot:

  1. Jump the canvas to a section the way ew-page-outline does when you click an entry. Clicking an item in a plugin's own list of sections can't scroll the editor to it.
  2. Edit an existing section. Because insertHTML replaces the current selection, the edit loop already works — but only if something can put the selection on the right node first. Without that, the only route left is writing the source via admin.da.live underneath a live collab session, which risks clobbering or being clobbered by the y.js document. We are not doing that, so editing is simply unavailable to plugins.

Proposed change

Expose what the outline rail already does internally, as one action:

if (action === 'selectSection') {
  const ok = editorView ? selectSection(editorView, details?.index) : false;
  channel.port1.postMessage({ action: 'selectSectionResult', details: { ok } });
  return;
}

backed by a selectSection(view, sectionIndex) helper in editor-utils/blocks.js, which reuses the same "split top-level nodes on horizontal_rule" walk that deleteSection and moveSection already use, and ends in TextSelection + scrollIntoView().

Selecting the whole section rather than just scrolling to it is deliberate: it gives the plugin the jump and leaves a replaceable range under sendHTML, so the existing insert action covers editing with no second API.

Happy to be told this belongs somewhere else, or should be shaped differently (a node/prose-index address rather than a section index would be more general, but section index is what the existing helpers already speak).

Not asking for

Anything that lets a plugin mutate the document without going through the editor. The value here is precisely that edits stay inside ProseMirror and collab.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ewExperience Workspace

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions