Skip to content

fix(import): map unsupported anchor targets to _self or _blank - #575

Open
tommy230 wants to merge 1 commit into
CoreBunch:mainfrom
tommy230:fix/import-unsupported-anchor-target
Open

tommy230 wants to merge 1 commit into
CoreBunch:mainfrom
tommy230:fix/import-unsupported-anchor-target

Conversation

@tommy230

@tommy230 tommy230 commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Importing HTML from a page builder can turn a working call-to-action into "Click here" pointing at #. Some page builders emit target="" on links whose target control was reset to default. The import copies that value straight into the node, and at publish time the link's schema rejects it. Because the props validator then falls back to the module defaults for the whole node, the published page loses the authored href and text, with no warning or error. target="_top" and named frame targets have the same effect.

<!-- source -->
<a href="/contact/" target="">Contact us</a>

<!-- published today -->
<a href="#" target="_self">Click here</a>

The cause is el.getAttribute('target') ?? '_self' in src/core/htmlImport/rules.ts: ?? only replaces null, so an empty string, _top or a named frame reaches the store as-is, and none of them is in AnchorTargetSchema (_self, _blank, _parent).

The fix:

  • AnchorTargetSchema moves from src/modules/base/shared/anchorTarget.ts to @core/htmlAttributes (next to resolveHtmlTag, for the same reason: the importer in src/core/ may not import src/modules/), with a new normalizeAnchorTarget() beside it that maps any value outside the schema onto the stored value that navigates the same way. Both anchor rules (a and a.btn) use it; the module-side file keeps the select options and the rel decision.
  • target="", a bare target and _top import as _self: outside a frameset they open in the same tab.
  • A named target (target="sidebar", _new) imports as _blank: with no frame of that name the browser opens a new tab.
  • _blank and _parent import unchanged, matched case-insensitively as HTML does (_BLANK is _blank). href and text are always kept.

_top and named targets are mapped rather than added to the schema: the editor's target control does not offer them, and without frames they behave like _self and _blank. A named target loses its tab reuse (a second click on the same name opens another tab instead of reusing the first).

Existing nodes that already carry an unsupported target are not rewritten by this change; that is the publisher's fallback behaviour, addressed in #574. The AI site_update_node_props tool can still write an unsupported target directly; #574 keeps that from costing the rest of the node.

Overlaps with #570 on shared/anchorTarget.ts and docs/features/modules.md, and with #571 on docs/features/html-import.md; whichever lands second gets a small rebase.

Verification

  • bun run build
  • bun run lint
  • bun test: 7062 pass, 0 fail
  • Docker/deployment check, if relevant: not relevant

New tests in src/__tests__/htmlImport/mapping.test.ts: 8 of 9 fail on main and pass with this change.

Checklist

  • Tests cover behavior changes.
  • Docs were updated when behavior, config, deployment, or public surfaces changed. (docs/features/html-import.md rule table and notes; the schema's new home in docs/features/modules.md and docs/reference/module-engine.md.)
  • No compatibility shim was added for old pre-release behavior.
  • No secrets, local databases, uploads, or generated artifacts are included.

🤖 Generated with Claude Code

@tommy230
tommy230 force-pushed the fix/import-unsupported-anchor-target branch from 401016f to a0771ba Compare September 28, 2026 23:59
@tommy230 tommy230 changed the title fix(import): normalise unsupported anchor targets to _self fix(import): normalise unsupported anchor targets Sep 28, 2026
The anchor import rules copied target="" (and _top or a named frame)
straight into the node. None of those values is in AnchorTargetSchema, so
the publisher's fallback replaced the whole link with module defaults and
the page shipped "Click here" pointing at "#". The schema now lives in
@core/htmlAttributes with a normalizeAnchorTarget() helper the importer
uses for both anchor rules: empty and _top import as _self, a named target
as _blank, keywords match case-insensitively, and href and text are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tommy230
tommy230 force-pushed the fix/import-unsupported-anchor-target branch from a0771ba to bbf731e Compare September 29, 2026 04:45
@tommy230 tommy230 changed the title fix(import): normalise unsupported anchor targets fix(import): map unsupported anchor targets to _self or _blank Sep 29, 2026
@tommy230
tommy230 marked this pull request as ready for review September 29, 2026 04:47

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant