adobe / adobe/da-live

Use text selection from ?select= when opening the editor from Sidekick

Open
#1,224 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
34
Forks
71
Avg merge
2d 11h
Merged PRs (30d)
29

Description

## Background
AEM Sidekick can switch from a rendered content page (preview/live) into the DA
editor. When the user has text selected on the content page, Sidekick appends
that selection to the DA edit URL as a `?select=` query param so the editor can
scroll to and re-select the same text.

(Native text fragments `:~:text=` can't be used here: the browser strips the
directive from `window.location`, DA content is rendered in shadow DOM and loads
asynchronously, and DA navigates same-document via `hashchange` — so none of the
conditions for native text fragments are met. Hence a query param that DA reads
and applies itself.)

Sidekick side: adobe/aem-sidekick#889 / adobe/aem-sidekick#891.

## Request
On editor load, if the URL has a `?select=` param, locate that text in the
ProseMirror document and select + scroll to it.

## URL / param format
```
https://da.live/edit?select=Lorem+ipsum+dolor#/org/site/path
```
- Single `select` param, standard URL-encoded (spaces as `+`).
- Read it with `URLSearchParams.get('select')`, which decodes it for you:
```js
const select = new URL(window.location.href).searchParams.get('select');
```

## When to apply — on initial collab sync (no polling)
The document content arrives over the Yjs/WebSocket collab connection, so apply
once the provider has synced. `onWsSync` already exists in
`blocks/edit/prose/index.js` and fires once (or immediately if already synced),
self-removes, and defers a tick so `y-prosemirror` can flush into the PM doc:

```js
// in initProse, alongside the existing sync-gated setup
onWsSync(wsProvider, () => applySelectFromUrl());
```

Guard against re-applying on in-tab hash navigations to another doc:

```js
let selectApplied = false;
function applySelectFromUrl() {
if (selectApplied) return;
const select = new URL(window.location.href).searchParams.get('select');
if (!select) return;
selectApplied = true;

const { view } = window;
const found = findRange(view.state.doc, select); // { from, to } | null
if (!found) return;
const sel = TextSelection.create(view.state.doc, found.from, found.to);
view.dispatch(view.state.tr.setSelection(sel).scrollIntoView());
view.focus();
}
```

## Locating the text (`findRange`)
Build a normalized flat-text index of the doc with a position map, `indexOf` the
selected text, and map back to ProseMirror positions. Normalize whitespace so
rendered-vs-source differences don't prevent a match. On multiple occurrences,
first match wins for now (see below).

## Keep the param in the URL
Do **not** strip `?select=` after applying it — users share these URLs to point
each other at a specific selection. (The `selectApplied` guard prevents
re-triggering within the same page load.)

## Notes / caveats
- Match against `window.view.state.doc` (source), which can differ from the
rendered page for structured blocks/metadata — best-effort for those, reliable
for prose.
- **Duplicate text:** if the selected text appears more than once, the first
match wins. Sidekick can later send a few words of surrounding context to
disambiguate (e.g. `selectPrefix`/`selectSuffix`); deferred until users report
it as a problem.
- The value is only ever used for an in-document text search (never injected as
HTML), so there's no XSS surface.

## Acceptance
- Opening a DA edit URL with `?select=` scrolls to and selects the referenced
text once content has synced.
- The param remains in the URL and isn't re-applied on subsequent in-tab
navigations.

Contributor guide

Open the contributing guide

Research direction

The entry point is blocks/edit/prose/index.js; read initProse and the existing onWsSync setup, then trace window.view.state.doc and ProseMirror selection handling. Done means a synced URL with ?select= selects and scrolls to the first normalized text match, preserves the parameter, and does not reapply after in-tab navigation.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.