Rich Text Editor: Migrate inline RTE blocks from data-content-udi to data-content-key (closes #23224) - #23259
Conversation
|
Claude finished @AndyButland's task in 2m 46s —— View job PR ReviewTarget: Fixes the regression from #22980 where adding a trailing
Suggestions
Approved with Suggestions for improvementGood to go — the regex change is minimal, well-reasoned, and consistent with the runtime parser. Tests cover the important cross-variant cases. The suggestion above is strictly additive and does not block merging. |
There was a problem hiding this comment.
Pull request overview
Fixes the v13→v15+ upgrade migration for inline RTE blocks (<umb-rte-block-inline>) so legacy data-content-udi="umb://element/{guid}" references are rewritten to data-content-key="{dashed-guid}", preventing inline blocks from becoming “unplaced” and hoisted/dropped in the editor.
Changes:
- Expanded the v15 upgrade migration regex to match both
<umb-rte-block>and<umb-rte-block-inline>opening/closing tags without reintroducing sibling-collapsing. - Added unit tests covering inline conversion, mixed inline/block siblings, class attribute preservation, malformed UDI behavior, and match-count behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/RteBlockHelperTests.cs | Adds inline and mixed-sibling coverage to prevent regressions in UDI→key migration. |
| src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/LocalLinks/RteBlockHelper.cs | Updates the migration regex to match both block and inline RTE block tag variants. |
Completes the ConvertBlockUdisToKeys parity matrix: there was an inline+block and block+inline assertion but no inline+inline one, leaving a gap where a future regression could collapse a consecutive inline pair into a single match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…data-content-key (closes #23224) (#23259) * Fix regression in migration for umb-rte-block-inline blocks. * Add inline-inline sibling parity test for RTE block migration Completes the ConvertBlockUdisToKeys parity matrix: there was an inline+block and block+inline assertion but no inline+inline one, leaving a gap where a future regression could collapse a consecutive inline pair into a single match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Description
Rich Text Editor inline blocks (
<umb-rte-block-inline>) created in Umbraco 13 were not being migrated from the legacydata-content-udi="umb://element/{guid}"attribute to the v15+data-content-key="{dashed-guid}"attribute during upgrade. As a result the block could not be matched to its content on load, so it was pulled out of the text flow and hoisted elsewhere in the document (and dropped on the next save).The fix is a one-line change to the migration regex in
RteBlockHelper.BlockRegex()so it also matches the-inlinetag variant.Fixes #23224
Where the issue came from
This is a regression introduced by #22980 (shipped in 17.5), which fixed the block-level sibling-collapse bug from #22979.
The tell is in the closing-tag part of the regex:
umb-rte-block-inline.*<\/umb-rte-block— greedy, no trailing><\/umb-rte-blockprefix matches inside</umb-rte-block-inline>).*?<\/umb-rte-block>— non-greedy, added></umb-rte-block>cannot match</umb-rte-block-inline>Making the pattern non-greedy and adding the trailing
>correctly fixed the block-level sibling collapse, but the added>meant the closing tag of the inline variant (</umb-rte-block-inline>) no longer matched — so isolated inline blocks stopped being converted. In other words, #22980 traded one failure mode for another on the inline variant.Note the block metadata (
blocks.contentData[].key) has always been normalized correctly; only the markup attribute was left behind, which is why an unmigrated inline block becomes "unplaced" and is hoisted out of position by the editor on load.The fix
src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/LocalLinks/RteBlockHelper.cs— add(?:-inline)?to both tag ends of the migration regex (mirrors the runtime parser inRichTextParsingRegexes.csand the v13 parser):The non-greedy
.*?combined with the two-variant closing tag means the match always stops at the nearest closing tag of either variant, so a mix of inline and block-level siblings never collapse together, and isolated inline blocks still match.Consistent with #22980, this corrects the existing
V_15_0_0migration rather than adding a new forward migration.Testing
Automated
Extended
RteBlockHelperTestswith inline coverage:data-content-key;umb://element/in either);classattribute converts, preserving the class;BlockRegexproduces one match per element for a mixed inline/block-level sequence.Red/green verified: with the original 17.5 regex the 6 new tests fail; with the fix all tests pass.
Manual (v13 → v17 upgrade)
Created a v13 RTE with an inline block (Element Type added as a block on the RTE data type, "Display inline with text" enabled), placed it inline within a paragraph, then upgraded.
Before (v13 stored markup):
After upgrade — WITHOUT the fix (
v17/dev): the block is hoisted to the top of the document and its original inline position is lost:(The
data-content-keyhere is the editor re-emitting the now-unplaced block fromcontentDataat the document start — not the migration doing its job. The stored markup still haddata-content-udiat the real position.)After upgrade — WITH the fix (this branch): the block is migrated in place and stays inline where it belongs:
(The transient
ng-scope ng-isolate-scopeclass and the<!--Umbraco-Block-->placeholder comment are stripped downstream by the Tiptap editor on load/save, not by the migration.)