@heartlandone/vega 2.95.0 → 2.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/{app-globals-76815382.js → app-globals-38afea36.js} +7 -7
- package/dist/cjs/{code-block-493c7ce7.js → code-block-4126dc3b.js} +1501 -55
- package/dist/cjs/{component-value-history-controller-slimmer.abstract-ab21fcbf.js → component-value-history-controller-slimmer.abstract-38ba956e.js} +2 -2
- package/dist/cjs/{content-state-fc34a814.js → content-state-50e8a03c.js} +142 -580
- package/dist/cjs/{element-appender-slimmer-1d6323c2.js → element-appender-slimmer-7773fdab.js} +115 -0
- package/dist/cjs/{image-annotation-action-7c4cd316.js → image-annotation-action-89363de8.js} +2 -2
- package/dist/cjs/{image-extension-30a7c10f.js → image-extension-c881c454.js} +2 -2
- package/dist/cjs/index.cjs.js +10 -10
- package/dist/cjs/{link-extension-92a63cb7.js → link-extension-b7f99a52.js} +2 -2
- package/dist/cjs/loader.cjs.js +7 -7
- package/dist/cjs/{public-rules-9e1ea1d9.js → public-rules-72894208.js} +3 -3
- package/dist/cjs/{range-30219330.js → range-95d41dea.js} +1 -1
- package/dist/cjs/{rich-text-editor-required-rule-23bf7485.js → rich-text-editor-required-rule-4d6d2493.js} +1 -1
- package/dist/cjs/{split-cell-operation-43752212.js → split-cell-operation-70be116d.js} +2 -2
- package/dist/cjs/{token-extension-d123d9d0.js → token-extension-eb828948.js} +35 -11
- package/dist/cjs/vega-code-block.cjs.entry.js +3 -3
- package/dist/cjs/vega-date-picker_2.cjs.entry.js +1 -1
- package/dist/cjs/vega-dropdown_5.cjs.entry.js +27 -4
- package/dist/cjs/vega-env-manager-23b8b23c.js +2 -2
- package/dist/cjs/vega-popover_2.cjs.entry.js +1 -1
- package/dist/cjs/vega-rich-text-content.cjs.entry.js +58 -9
- package/dist/cjs/vega-rich-text-editor_4.cjs.entry.js +608 -90
- package/dist/cjs/vega-rich-text-table-properties_3.cjs.entry.js +3 -3
- package/dist/cjs/vega-section-title.cjs.entry.js +896 -14
- package/dist/cjs/vega-time-picker_2.cjs.entry.js +1 -1
- package/dist/cjs/vega-tooltip_2.cjs.entry.js +1 -1
- package/dist/cjs/vega.cjs.js +7 -7
- package/dist/collection/components/vega-combo-box/vega-combo-box.js +2 -2
- package/dist/collection/components/vega-dropdown/vega-dropdown.js +30 -7
- package/dist/collection/components/vega-input-select/vega-input-select.js +2 -2
- package/dist/collection/components/vega-rich-text-content/vega-rich-text-content.css +4 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-delete-node-content-strategy.js +29 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-delete-text-or-decorator-node-strategy.js +10 -1
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-transform-to-list-strategy.js +8 -3
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-annotation-strategy.abstract.js +60 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-item-replace-nest-list-strategy.js +36 -4
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-items-strategy.abstract.js +27 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-nest-items-strategy.js +74 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-remove-list-item-strategy.js +81 -1
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-selection.js +30 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-list-strategy.js +160 -9
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-paragraph-strategy.js +376 -10
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-unnest-items-strategy.js +104 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.js +2 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/nest-list-items-action.js +12 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/unnest-list-items-action.js +12 -0
- package/dist/collection/components/vega-rich-text-editor/dto/annotations/list-annotation.js +12 -0
- package/dist/collection/components/vega-rich-text-editor/dto/blocks/list-block.js +10 -1
- package/dist/collection/components/vega-rich-text-editor/dto/blocks/list-item-block.js +11 -3
- package/dist/collection/components/vega-rich-text-editor/dto/content-state.js +7 -1
- package/dist/collection/components/vega-rich-text-editor/dto/filter-styles-strategies/list-block/list-block-filter-styles-strategy.js +8 -4
- package/dist/collection/components/vega-rich-text-editor/dto/renderers/blocks/list-block-renderer.js +34 -1
- package/dist/collection/components/vega-rich-text-editor/dto/renderers/blocks/list-item-block-renderer.js +20 -3
- package/dist/collection/components/vega-rich-text-editor/extensions/table/annotation-handler/table-annotation-handler-base.js +25 -1
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/element-to-dto-strategy/li-to-rte-list-item-block-strategy.js +2 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/abstract-delete-content-handler.js +29 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/bullets-numbers-toolbar-button-slimmer.js +30 -1
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/abstract-list-keyboard-handler.js +204 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-shift-tab-outdent-handler.js +42 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-tab-indent-handler.js +34 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/list-keyboard-slimmer.js +180 -0
- package/dist/collection/components/vega-section-title/slimmers/a11y-tree/build-section-title-a11y-tree.js +54 -0
- package/dist/collection/components/vega-section-title/slimmers/renderers/vega-section-title-renderer.js +4 -4
- package/dist/collection/components/vega-section-title/vega-section-title.js +18 -2
- package/dist/collection/helpers/a11y-tree/a11y-node-dto.js +210 -0
- package/dist/collection/helpers/a11y-tree/a11y-tree-applier.js +189 -0
- package/dist/collection/helpers/a11y-tree/a11y-tree.types.js +48 -0
- package/dist/collection/helpers/a11y-tree/strategies/baseline-strategy.js +78 -0
- package/dist/collection/helpers/a11y-tree/strategies/firefox-nvda-strategy.js +56 -0
- package/dist/collection/helpers/a11y-tree/strategies/webkit-voiceover-strategy.js +140 -0
- package/dist/collection/helpers/a11y-tree/strategy-resolver.js +172 -0
- package/dist/collection/helpers/slimmers/a11y-tree-slimmer.js +54 -0
- package/dist/collection/helpers/slimmers/element-appender/element-appender-slimmer.js +29 -0
- package/dist/collection/helpers/slimmers/element-appender/visibility-modifiers/clip-on-scroll-modifier.js +70 -0
- package/dist/collection/helpers/slimmers/element-appender/visibility-modifiers/visibility-modifier.interface.js +1 -0
- package/dist/collection/helpers/ui/element-appender.js +16 -0
- package/dist/esm/{app-globals-eafcc7a1.js → app-globals-d7b651c1.js} +7 -7
- package/dist/esm/{code-block-e12588fe.js → code-block-0a88b481.js} +1495 -51
- package/dist/esm/{component-value-history-controller-slimmer.abstract-4e8eb313.js → component-value-history-controller-slimmer.abstract-6846edfa.js} +2 -2
- package/dist/esm/{content-state-8032467a.js → content-state-79ca99e5.js} +105 -541
- package/dist/esm/{element-appender-slimmer-7fcb944b.js → element-appender-slimmer-73ad10ae.js} +115 -0
- package/dist/esm/{image-annotation-action-08a20d5e.js → image-annotation-action-bb299ef1.js} +2 -2
- package/dist/esm/{image-extension-b6c7e4a7.js → image-extension-48a96f98.js} +2 -2
- package/dist/esm/index.js +8 -8
- package/dist/esm/{link-extension-97fcb8fb.js → link-extension-09534514.js} +2 -2
- package/dist/esm/loader.js +7 -7
- package/dist/esm/{public-rules-c06f0d2a.js → public-rules-5eb03ef0.js} +3 -3
- package/dist/esm/{range-e999837f.js → range-d4deb7df.js} +1 -1
- package/dist/esm/{rich-text-editor-required-rule-71f8ee98.js → rich-text-editor-required-rule-5bbbce23.js} +1 -1
- package/dist/esm/{split-cell-operation-359f8082.js → split-cell-operation-7f3058ad.js} +2 -2
- package/dist/esm/{token-extension-f5bf9c21.js → token-extension-40c32bcc.js} +30 -6
- package/dist/esm/vega-code-block.entry.js +3 -3
- package/dist/esm/vega-date-picker_2.entry.js +1 -1
- package/dist/esm/vega-dropdown_5.entry.js +27 -4
- package/dist/esm/vega-env-manager-8f8dc473.js +2 -2
- package/dist/esm/vega-popover_2.entry.js +1 -1
- package/dist/esm/vega-rich-text-content.entry.js +58 -9
- package/dist/esm/vega-rich-text-editor_4.entry.js +604 -86
- package/dist/esm/vega-rich-text-table-properties_3.entry.js +3 -3
- package/dist/esm/vega-section-title.entry.js +897 -15
- package/dist/esm/vega-time-picker_2.entry.js +1 -1
- package/dist/esm/vega-tooltip_2.entry.js +1 -1
- package/dist/esm/vega.js +7 -7
- package/dist/sri/vega-sri-manifest.json +94 -94
- package/dist/types/components/vega-combo-box/vega-combo-box.d.ts +6 -6
- package/dist/types/components/vega-dropdown/types.d.ts +2 -2
- package/dist/types/components/vega-dropdown/vega-dropdown.d.ts +32 -9
- package/dist/types/components/vega-input-select/vega-input-select.d.ts +6 -6
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-annotation-strategy.abstract.d.ts +36 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-item-replace-nest-list-strategy.d.ts +14 -2
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-items-strategy.abstract.d.ts +22 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-nest-items-strategy.d.ts +21 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-remove-list-item-strategy.d.ts +14 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-selection.d.ts +15 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-list-strategy.d.ts +30 -3
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-paragraph-strategy.d.ts +99 -3
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-unnest-items-strategy.d.ts +22 -0
- package/dist/types/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.d.ts +2 -0
- package/dist/types/components/vega-rich-text-editor/dto/actions/nest-list-items-action.d.ts +11 -0
- package/dist/types/components/vega-rich-text-editor/dto/actions/unnest-list-items-action.d.ts +11 -0
- package/dist/types/components/vega-rich-text-editor/dto/annotations/list-annotation.d.ts +8 -0
- package/dist/types/components/vega-rich-text-editor/dto/blocks/list-block.d.ts +6 -1
- package/dist/types/components/vega-rich-text-editor/dto/blocks/list-item-block.d.ts +5 -1
- package/dist/types/components/vega-rich-text-editor/dto/content-state.d.ts +2 -2
- package/dist/types/components/vega-rich-text-editor/dto/renderers/blocks/list-block-renderer.d.ts +2 -0
- package/dist/types/components/vega-rich-text-editor/dto/renderers/blocks/list-item-block-renderer.d.ts +8 -0
- package/dist/types/components/vega-rich-text-editor/extensions/table/annotation-handler/table-annotation-handler-base.d.ts +18 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/bullets-numbers-toolbar-button-slimmer.d.ts +8 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/abstract-list-keyboard-handler.d.ts +99 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-shift-tab-outdent-handler.d.ts +15 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-tab-indent-handler.d.ts +15 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/list-keyboard-slimmer.d.ts +73 -0
- package/dist/types/components/vega-section-title/slimmers/a11y-tree/build-section-title-a11y-tree.d.ts +41 -0
- package/dist/types/components/vega-section-title/vega-section-title.d.ts +9 -0
- package/dist/types/components.d.ts +10 -10
- package/dist/types/helpers/a11y-tree/a11y-node-dto.d.ts +173 -0
- package/dist/types/helpers/a11y-tree/a11y-tree-applier.d.ts +28 -0
- package/dist/types/helpers/a11y-tree/a11y-tree.types.d.ts +137 -0
- package/dist/types/helpers/a11y-tree/strategies/baseline-strategy.d.ts +18 -0
- package/dist/types/helpers/a11y-tree/strategies/firefox-nvda-strategy.d.ts +16 -0
- package/dist/types/helpers/a11y-tree/strategies/webkit-voiceover-strategy.d.ts +23 -0
- package/dist/types/helpers/a11y-tree/strategy-resolver.d.ts +59 -0
- package/dist/types/helpers/slimmers/a11y-tree-slimmer.d.ts +49 -0
- package/dist/types/helpers/slimmers/element-appender/element-appender-slimmer.d.ts +9 -0
- package/dist/types/helpers/slimmers/element-appender/visibility-modifiers/clip-on-scroll-modifier.d.ts +37 -0
- package/dist/types/helpers/slimmers/element-appender/visibility-modifiers/visibility-modifier.interface.d.ts +56 -0
- package/dist/types/helpers/ui/element-appender.d.ts +7 -0
- package/dist/vega/index.esm.js +1 -1
- package/dist/vega/{p-9c39f90b.entry.js → p-1dfbc542.entry.js} +1 -1
- package/dist/vega/{p-e235020b.entry.js → p-22cc174e.entry.js} +1 -1
- package/dist/vega/{p-b187b82d.entry.js → p-2df5d59b.entry.js} +1 -1
- package/dist/vega/{p-f7e459cd.js → p-312d8205.js} +1 -1
- package/dist/vega/{p-a7209700.js → p-3345d903.js} +1 -1
- package/dist/vega/{p-02355de8.js → p-3c23ec90.js} +1 -1
- package/dist/vega/p-55e0014a.js +3 -0
- package/dist/vega/p-5f377954.js +1 -1
- package/dist/vega/p-65fee02f.entry.js +1 -0
- package/dist/vega/p-6a51d720.js +1 -0
- package/dist/vega/{p-fe24b459.js → p-6c7b6d45.js} +1 -1
- package/dist/vega/{p-579cdeae.js → p-84b7a775.js} +1 -1
- package/dist/vega/{p-df828d90.entry.js → p-96da7d30.entry.js} +1 -1
- package/dist/vega/{p-88be9ec5.js → p-9d3f69cb.js} +1 -1
- package/dist/vega/{p-8a001caa.js → p-9f11b579.js} +1 -1
- package/dist/vega/{p-ba2b9663.entry.js → p-acaff62d.entry.js} +1 -1
- package/dist/vega/p-b63319e9.entry.js +1 -0
- package/dist/vega/{p-c079c935.entry.js → p-b660f38c.entry.js} +1 -1
- package/dist/vega/p-b8ffa42f.entry.js +1 -0
- package/dist/vega/{p-4fe40b76.js → p-c4564904.js} +1 -1
- package/dist/vega/p-d9158512.js +1 -0
- package/dist/vega/p-e62d41ee.js +1 -0
- package/dist/vega/{p-9f7154d2.js → p-ec5dee32.js} +1 -1
- package/dist/vega/{p-05d04c07.entry.js → p-f29d9707.entry.js} +1 -1
- package/dist/vega/vega.esm.js +1 -1
- package/package.json +3 -2
- package/dist/vega/p-0be4df0a.js +0 -1
- package/dist/vega/p-38c9d782.js +0 -1
- package/dist/vega/p-513bc0d9.js +0 -1
- package/dist/vega/p-8d4b85e7.entry.js +0 -1
- package/dist/vega/p-c5d3b008.entry.js +0 -1
- package/dist/vega/p-d25ca0c3.entry.js +0 -1
- package/dist/vega/p-f4da615a.js +0 -3
|
@@ -1,36 +1,187 @@
|
|
|
1
1
|
import { AppendChildrenAction } from '../../actions/append-child-nodes-action';
|
|
2
2
|
import { InsertChildrenAfterAction } from '../../actions/insert-children-after-block';
|
|
3
3
|
import { RemoveChildrenAction } from '../../actions/remove-child-action';
|
|
4
|
+
import { ReplaceNestListAction } from '../../actions/replace-nest-list-action';
|
|
4
5
|
import { SyncUpSelectionAction } from '../../actions/sync-up-selection-action';
|
|
5
|
-
import {
|
|
6
|
+
import { RTEListBlock } from '../../blocks/list-block';
|
|
7
|
+
import { RTEListItemBlock } from '../../blocks/list-item-block';
|
|
8
|
+
import { normalizeMixedListSelection } from './list-transform-selection';
|
|
9
|
+
import { ListAnnotationStrategy } from './list-annotation-strategy.abstract';
|
|
6
10
|
/**
|
|
7
11
|
* Convert the selected blocks to list strategy.
|
|
8
12
|
*/
|
|
9
|
-
export class ListTransformToListStrategy extends
|
|
13
|
+
export class ListTransformToListStrategy extends ListAnnotationStrategy {
|
|
10
14
|
/**
|
|
11
15
|
* @inheritDoc
|
|
12
16
|
*/
|
|
13
17
|
handleAction(action, target) {
|
|
18
|
+
var _a;
|
|
14
19
|
const selectedBlocks = action.selectedBlocks;
|
|
15
|
-
const bulletList = target.parent.createList(action.listType);
|
|
16
20
|
const isSameList = selectedBlocks.every((block) => block.parent === target);
|
|
21
|
+
const rootContent = this.getRootContent(target);
|
|
22
|
+
if (!rootContent) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Nested list case: target.parent is RTEListItemBlock, not VegaRTEContent.
|
|
26
|
+
// Replace the entry in the parent item's nestList using the existing ReplaceNestListAction.
|
|
27
|
+
if (target.parent instanceof RTEListItemBlock) {
|
|
28
|
+
if (isSameList) {
|
|
29
|
+
const newList = this.createListFromSource(rootContent, target, action.listType);
|
|
30
|
+
newList.apply(new AppendChildrenAction(target.children));
|
|
31
|
+
const parentListItem = target.parent;
|
|
32
|
+
const newNestList = ((_a = parentListItem.nestList) !== null && _a !== void 0 ? _a : []).map((list) => (list === target ? newList : list));
|
|
33
|
+
// Adjacent same-type merge is handled automatically by ListItemReplaceNestListStrategy.
|
|
34
|
+
parentListItem.apply(new ReplaceNestListAction(newNestList));
|
|
35
|
+
selectedBlocks.forEach((block) => block.children.map((node) => node.apply(new SyncUpSelectionAction())));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.handleCrossListTransform(action, target);
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Root list case: target.parent is VegaRTEContent.
|
|
43
|
+
// When all selected blocks are list items from different lists, convert each
|
|
44
|
+
// affected list's type in place (preserving nesting), then normalize adjacent
|
|
45
|
+
// same-type root lists into one.
|
|
46
|
+
if (!isSameList && selectedBlocks.every((block) => block instanceof RTEListItemBlock)) {
|
|
47
|
+
const affectedLists = new Set(selectedBlocks.map((block) => block.parent));
|
|
48
|
+
// Track which root lists result from conversion (new lists replace old ones).
|
|
49
|
+
const convertedRootLists = new Set();
|
|
50
|
+
affectedLists.forEach((list) => {
|
|
51
|
+
if (list.type !== action.listType) {
|
|
52
|
+
this.convertListTypeInPlace(list, action.listType);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// Collect current top-level lists that contain any selected item, grouped
|
|
56
|
+
// by their root or HTML-block container.
|
|
57
|
+
const affectedContainers = new Set();
|
|
58
|
+
selectedBlocks.forEach((block) => {
|
|
59
|
+
const parentList = block.parent;
|
|
60
|
+
if (!(parentList.parent instanceof RTEListItemBlock)) {
|
|
61
|
+
convertedRootLists.add(parentList);
|
|
62
|
+
affectedContainers.add(parentList.parent);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// Only merge adjacent root lists when BOTH are affected by this transform.
|
|
66
|
+
affectedContainers.forEach((container) => {
|
|
67
|
+
for (let i = 0; i < container.children.length - 1;) {
|
|
68
|
+
const current = container.children[i];
|
|
69
|
+
const next = container.children[i + 1];
|
|
70
|
+
if (current instanceof RTEListBlock &&
|
|
71
|
+
next instanceof RTEListBlock &&
|
|
72
|
+
current.type === next.type &&
|
|
73
|
+
this.haveSameListAnnotations(current, next) &&
|
|
74
|
+
convertedRootLists.has(current) &&
|
|
75
|
+
convertedRootLists.has(next)) {
|
|
76
|
+
current.apply(new AppendChildrenAction([...next.children]));
|
|
77
|
+
container.apply(new RemoveChildrenAction(next));
|
|
78
|
+
convertedRootLists.delete(next);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
i++;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
selectedBlocks.forEach((block) => block.children.map((node) => node.apply(new SyncUpSelectionAction())));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const bulletList = this.createListFromSource(rootContent, target, action.listType);
|
|
89
|
+
const targetContainer = target.parent;
|
|
17
90
|
if (isSameList) {
|
|
18
91
|
// Select one or more list items belonging to the same list, and all items in this list should be updated
|
|
19
92
|
bulletList.apply(new AppendChildrenAction(target.children));
|
|
20
|
-
|
|
21
|
-
|
|
93
|
+
targetContainer.apply(new InsertChildrenAfterAction(target, bulletList));
|
|
94
|
+
targetContainer.apply(new RemoveChildrenAction(target));
|
|
22
95
|
selectedBlocks.forEach((block) => block.children.map((node) => node.apply(new SyncUpSelectionAction())));
|
|
23
96
|
}
|
|
24
97
|
else {
|
|
25
|
-
const
|
|
98
|
+
const mixedSelection = normalizeMixedListSelection(action.selectedBlocks, action.listType);
|
|
99
|
+
const listItems = mixedSelection.map((block) => rootContent.toListItem(block));
|
|
26
100
|
bulletList.apply(new AppendChildrenAction(listItems));
|
|
27
|
-
|
|
28
|
-
|
|
101
|
+
targetContainer.apply(new InsertChildrenAfterAction(target, bulletList));
|
|
102
|
+
mixedSelection.forEach((block) => {
|
|
29
103
|
block.parent.apply(new RemoveChildrenAction(block));
|
|
30
104
|
});
|
|
31
105
|
if (target.children.length === 0) {
|
|
32
|
-
|
|
106
|
+
targetContainer.apply(new RemoveChildrenAction(target));
|
|
33
107
|
}
|
|
34
108
|
}
|
|
35
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Convert a single list's type in place, preserving its items and their nested
|
|
112
|
+
* structure. Root lists are swapped in the content children; nested lists are
|
|
113
|
+
* swapped inside their parent item's nestList.
|
|
114
|
+
*
|
|
115
|
+
* @param {RTEListBlock} list - The list whose type should be converted.
|
|
116
|
+
* @param {RTEListBlock['type']} listType - The target list type.
|
|
117
|
+
*/
|
|
118
|
+
convertListTypeInPlace(list, listType) {
|
|
119
|
+
var _a;
|
|
120
|
+
const rootContent = this.getRootContent(list);
|
|
121
|
+
if (!rootContent) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const parent = list.parent;
|
|
125
|
+
const newList = this.createListFromSource(rootContent, list, listType);
|
|
126
|
+
newList.apply(new AppendChildrenAction([...list.children]));
|
|
127
|
+
if (parent instanceof RTEListItemBlock) {
|
|
128
|
+
// Adjacent same-type merge is handled automatically by ListItemReplaceNestListStrategy.
|
|
129
|
+
const newNestList = ((_a = parent.nestList) !== null && _a !== void 0 ? _a : []).map((entry) => entry === list ? newList : entry);
|
|
130
|
+
parent.apply(new ReplaceNestListAction(newNestList));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
parent.apply(new InsertChildrenAfterAction(list, newList));
|
|
134
|
+
parent.apply(new RemoveChildrenAction(list));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Handle the case where selected blocks span multiple nestLists under the same parent item.
|
|
139
|
+
* Transform each affected list and then merge adjacent same-type lists.
|
|
140
|
+
*
|
|
141
|
+
* @param {TransformListAction} action - The transform action with selection and target list type.
|
|
142
|
+
* @param {RTEListBlock} target - The nested list where transformation starts.
|
|
143
|
+
*/
|
|
144
|
+
handleCrossListTransform(action, target) {
|
|
145
|
+
if (!(target.parent instanceof RTEListItemBlock)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const rootContent = this.getRootContent(target);
|
|
149
|
+
if (!rootContent) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const parentListItem = target.parent;
|
|
153
|
+
const parentNestLists = parentListItem.nestList;
|
|
154
|
+
const affectedLists = new Set(action.selectedBlocks
|
|
155
|
+
.filter((block) => block instanceof RTEListItemBlock)
|
|
156
|
+
.map((block) => block.parent)
|
|
157
|
+
.filter((list) => parentNestLists.includes(list)));
|
|
158
|
+
if (!affectedLists.size) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const newNestList = parentNestLists.map((list) => {
|
|
162
|
+
if (!affectedLists.has(list)) {
|
|
163
|
+
return list;
|
|
164
|
+
}
|
|
165
|
+
const newList = this.createListFromSource(rootContent, list, action.listType);
|
|
166
|
+
newList.apply(new AppendChildrenAction(list.children));
|
|
167
|
+
return newList;
|
|
168
|
+
});
|
|
169
|
+
// Adjacent same-type merge is handled automatically by ListItemReplaceNestListStrategy.
|
|
170
|
+
parentListItem.apply(new ReplaceNestListAction(newNestList));
|
|
171
|
+
action.selectedBlocks.forEach((block) => block.children.map((node) => node.apply(new SyncUpSelectionAction())));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Create a replacement list through the owning content factory while retaining
|
|
175
|
+
* the source list's container annotations.
|
|
176
|
+
*
|
|
177
|
+
* @param {VegaRTEContent} rootContent - Editor content owning the factory.
|
|
178
|
+
* @param {RTEListBlock} source - List whose annotations should be retained.
|
|
179
|
+
* @param {RTEListBlock['type']} listType - Replacement list type.
|
|
180
|
+
* @returns {RTEListBlock} New annotated list shell.
|
|
181
|
+
*/
|
|
182
|
+
createListFromSource(rootContent, source, listType) {
|
|
183
|
+
const list = rootContent.createList(listType);
|
|
184
|
+
this.copyListAnnotations(source, list);
|
|
185
|
+
return list;
|
|
186
|
+
}
|
|
36
187
|
}
|
|
@@ -3,50 +3,416 @@ import { AppendChildrenAction } from '../../actions/append-child-nodes-action';
|
|
|
3
3
|
import { InsertChildrenAfterAction } from '../../actions/insert-children-after-block';
|
|
4
4
|
import { InsertChildrenBeforeAction } from '../../actions/insert-children-before-block';
|
|
5
5
|
import { RemoveChildrenAction } from '../../actions/remove-child-action';
|
|
6
|
+
import { ReplaceNestListAction } from '../../actions/replace-nest-list-action';
|
|
6
7
|
import { SyncUpSelectionAction } from '../../actions/sync-up-selection-action';
|
|
8
|
+
import { TransformParagraphAction } from '../../actions/transform-paragraph-action';
|
|
9
|
+
import { RTEHtmlBlock } from '../../blocks/html-block';
|
|
10
|
+
import { RTEListBlock } from '../../blocks/list-block';
|
|
11
|
+
import { RTEListItemBlock } from '../../blocks/list-item-block';
|
|
7
12
|
import { RTETextBlock } from '../../blocks/text-block';
|
|
8
|
-
import {
|
|
13
|
+
import { ListAnnotationStrategy } from './list-annotation-strategy.abstract';
|
|
9
14
|
/**
|
|
10
15
|
* Convert the selected list block to paragraph strategy.
|
|
11
16
|
*/
|
|
12
|
-
export class ListTransformToParagraphStrategy extends
|
|
17
|
+
export class ListTransformToParagraphStrategy extends ListAnnotationStrategy {
|
|
13
18
|
/**
|
|
14
19
|
* @inheritDoc
|
|
15
20
|
*/
|
|
16
21
|
handleAction(action, target) {
|
|
22
|
+
const selectedSegments = this.getSelectedSegments(action.selectedBlocks);
|
|
23
|
+
if (selectedSegments.length === 0 || !this.hasConsistentTargetAndRoot(selectedSegments, target)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.syncSelection(selectedSegments);
|
|
27
|
+
[...selectedSegments]
|
|
28
|
+
.reverse()
|
|
29
|
+
.forEach((segment) => this.transformSegment(segment));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Ensure the action is applied to the first selected item's parent list and
|
|
33
|
+
* every selected item belongs to the same editor content.
|
|
34
|
+
*
|
|
35
|
+
* @param {RTEListItemBlock[][]} selectedSegments - Normalized selection segments.
|
|
36
|
+
* @param {RTEListBlock} target - List receiving the transform action.
|
|
37
|
+
* @returns {boolean} Whether the target and root content are consistent.
|
|
38
|
+
*/
|
|
39
|
+
hasConsistentTargetAndRoot(selectedSegments, target) {
|
|
40
|
+
if (selectedSegments[0][0].parent !== target) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const targetRoot = this.getRootContent(target);
|
|
44
|
+
return Boolean(targetRoot &&
|
|
45
|
+
selectedSegments.every((segment) => segment.every((item) => this.getRootContent(item) === targetRoot)));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Capture selected text nodes in document order before reverse-order tree
|
|
49
|
+
* mutations move them into paragraphs.
|
|
50
|
+
*
|
|
51
|
+
* @param {RTEListItemBlock[][]} selectedSegments - Normalized selection segments.
|
|
52
|
+
*/
|
|
53
|
+
syncSelection(selectedSegments) {
|
|
54
|
+
selectedSegments.forEach((segment) => {
|
|
55
|
+
segment.forEach((block) => {
|
|
56
|
+
block.children.forEach((node) => node.apply(new SyncUpSelectionAction()));
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Transform one normalized segment without recursively dispatching another
|
|
62
|
+
* flushable action.
|
|
63
|
+
*
|
|
64
|
+
* @param {RTEListItemBlock[]} segment - Contiguous items sharing one parent list.
|
|
65
|
+
*/
|
|
66
|
+
transformSegment(segment) {
|
|
67
|
+
const segmentTarget = segment[0].parent;
|
|
68
|
+
const normalizedAction = new TransformParagraphAction(segment);
|
|
69
|
+
if (segmentTarget.parent instanceof RTEListItemBlock) {
|
|
70
|
+
this.handleNestedListCase(normalizedAction, segmentTarget);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.handleRootListCase(normalizedAction, segmentTarget);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Handle the case where the target list is at root level (parent is VegaRTEContent).
|
|
77
|
+
*
|
|
78
|
+
* @param {TransformParagraphAction} action - The paragraph transform action.
|
|
79
|
+
* @param {RTEListBlock} target - The root list being transformed.
|
|
80
|
+
*/
|
|
81
|
+
handleRootListCase(action, target) {
|
|
82
|
+
// handleAction validates that the target belongs to an editor content root.
|
|
83
|
+
const rootContent = this.getRootContent(target);
|
|
17
84
|
let isSelectedFirstBlock = false;
|
|
18
85
|
let isSelectedLastBlock = false;
|
|
19
86
|
const selectedBlocks = action.selectedBlocks;
|
|
20
|
-
|
|
21
|
-
|
|
87
|
+
// Build an operation-local insertion sequence. Paragraphs are merge
|
|
88
|
+
// boundaries; only consecutive same-type promoted lists are merged.
|
|
89
|
+
const insertionBlocks = [];
|
|
90
|
+
selectedBlocks.forEach((block) => {
|
|
91
|
+
var _a;
|
|
22
92
|
if (block === target.children[0])
|
|
23
93
|
isSelectedFirstBlock = true;
|
|
24
94
|
if (block === target.children[target.children.length - 1])
|
|
25
95
|
isSelectedLastBlock = true;
|
|
26
|
-
|
|
96
|
+
insertionBlocks.push(this.toParagraph(block));
|
|
97
|
+
for (const nestList of (_a = block.nestList) !== null && _a !== void 0 ? _a : []) {
|
|
98
|
+
this.appendListBlock(insertionBlocks, nestList);
|
|
99
|
+
}
|
|
27
100
|
});
|
|
28
101
|
if (isSelectedFirstBlock) {
|
|
29
|
-
target.parent.apply(new InsertChildrenBeforeAction(target, ...
|
|
102
|
+
target.parent.apply(new InsertChildrenBeforeAction(target, ...insertionBlocks));
|
|
30
103
|
}
|
|
31
104
|
else if (isSelectedLastBlock) {
|
|
32
|
-
target.parent.apply(new InsertChildrenAfterAction(target, ...
|
|
105
|
+
target.parent.apply(new InsertChildrenAfterAction(target, ...insertionBlocks));
|
|
33
106
|
}
|
|
34
107
|
else {
|
|
35
108
|
const startIndex = target.children.indexOf(selectedBlocks[0]);
|
|
36
109
|
const lastIndex = target.children.indexOf(selectedBlocks[selectedBlocks.length - 1]);
|
|
37
|
-
const firstBulletList =
|
|
110
|
+
const firstBulletList = this.createListFromSource(rootContent, target);
|
|
38
111
|
firstBulletList.apply(new AppendChildrenAction(target.children.slice(0, startIndex)));
|
|
39
|
-
const lastBulletList =
|
|
112
|
+
const lastBulletList = this.createListFromSource(rootContent, target);
|
|
40
113
|
lastBulletList.apply(new AppendChildrenAction(target.children.slice(lastIndex + 1)));
|
|
41
|
-
|
|
114
|
+
// Merge last insertionBlock with lastBulletList if same type
|
|
115
|
+
const lastInsertion = insertionBlocks[insertionBlocks.length - 1];
|
|
116
|
+
if (lastInsertion instanceof RTEListBlock &&
|
|
117
|
+
lastBulletList.children.length > 0 &&
|
|
118
|
+
lastInsertion.type === lastBulletList.type &&
|
|
119
|
+
this.haveSameListAnnotations(lastInsertion, lastBulletList)) {
|
|
120
|
+
lastInsertion.apply(new AppendChildrenAction(lastBulletList.children));
|
|
121
|
+
target.parent.apply(new InsertChildrenBeforeAction(target, firstBulletList, ...insertionBlocks));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
target.parent.apply(new InsertChildrenBeforeAction(target, firstBulletList, ...insertionBlocks, lastBulletList));
|
|
125
|
+
}
|
|
42
126
|
target.parent.apply(new RemoveChildrenAction(target));
|
|
43
127
|
}
|
|
44
128
|
selectedBlocks.map((block) => {
|
|
129
|
+
// Clear nestList before removal to prevent ListRemoveListItemStrategy
|
|
130
|
+
// from promoting the same nested lists a second time.
|
|
131
|
+
block.nestList = [];
|
|
45
132
|
target.apply(new RemoveChildrenAction(block));
|
|
46
133
|
});
|
|
47
134
|
if (target.children.length === 0) {
|
|
48
135
|
target.parent.apply(new RemoveChildrenAction(target));
|
|
49
136
|
}
|
|
137
|
+
else if (isSelectedFirstBlock) {
|
|
138
|
+
// When removing the first item(s), a promoted same-type nestList (last
|
|
139
|
+
// insertionBlock) ends up immediately before the remaining target. Merge
|
|
140
|
+
// them so the user doesn't see two adjacent same-type lists.
|
|
141
|
+
const lastInserted = insertionBlocks[insertionBlocks.length - 1];
|
|
142
|
+
if (lastInserted instanceof RTEListBlock &&
|
|
143
|
+
lastInserted.type === target.type &&
|
|
144
|
+
this.haveSameListAnnotations(lastInserted, target)) {
|
|
145
|
+
lastInserted.apply(new AppendChildrenAction([...target.children]));
|
|
146
|
+
target.parent.apply(new RemoveChildrenAction(target));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Handle the case where the target list is nested (parent is RTEListItemBlock).
|
|
152
|
+
*
|
|
153
|
+
* Algorithm:
|
|
154
|
+
* 1. Build the ancestor path from root list down to the target nested list.
|
|
155
|
+
* 2. At each level on the path, collect "trailing" items (items after the ancestor).
|
|
156
|
+
* 3. Trim each list along the path to keep only the "before" portion.
|
|
157
|
+
* 4. Collect trailing items from all levels + selected item's own nestList children.
|
|
158
|
+
* 5. Group trailing items into lists by consecutive type.
|
|
159
|
+
* 6. Insert into content: [before-root-list, paragraphs, ...after-lists].
|
|
160
|
+
*
|
|
161
|
+
* @param {TransformParagraphAction} action - The paragraph transform action.
|
|
162
|
+
* @param {RTEListBlock} target - The nested list being transformed.
|
|
163
|
+
*/
|
|
164
|
+
handleNestedListCase(action, target) {
|
|
165
|
+
const selectedBlocks = action.selectedBlocks;
|
|
166
|
+
const rootContent = this.getRootContent(target);
|
|
167
|
+
const selectedItem = selectedBlocks[0];
|
|
168
|
+
const selectedIndex = target.children.indexOf(selectedItem);
|
|
169
|
+
// Emit each selected item as paragraph + its own nested lists so that
|
|
170
|
+
// selecting multiple levels never moves a child list past another paragraph.
|
|
171
|
+
const insertions = [];
|
|
172
|
+
selectedBlocks.forEach((block) => {
|
|
173
|
+
var _a;
|
|
174
|
+
insertions.push(this.toParagraph(block));
|
|
175
|
+
for (const nestList of (_a = block.nestList) !== null && _a !== void 0 ? _a : []) {
|
|
176
|
+
this.appendListBlock(insertions, nestList);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
const lastSelectedIndex = target.children.indexOf(selectedBlocks[selectedBlocks.length - 1]);
|
|
180
|
+
// Collect trailing items from the nested list (items AFTER the last selected)
|
|
181
|
+
const nestedTrailingItems = target.children.slice(lastSelectedIndex + 1);
|
|
182
|
+
const ancestorPath = [];
|
|
183
|
+
let currentList = target;
|
|
184
|
+
while (currentList.parent instanceof RTEListItemBlock) {
|
|
185
|
+
const parentItem = currentList.parent;
|
|
186
|
+
const grandParentList = parentItem.parent;
|
|
187
|
+
const ancestorIndex = grandParentList.children.indexOf(parentItem);
|
|
188
|
+
// Collect nestLists of parentItem that are AFTER currentList
|
|
189
|
+
const parentNestLists = parentItem.nestList;
|
|
190
|
+
const nestListIndex = parentNestLists.indexOf(currentList);
|
|
191
|
+
const trailingNestLists = parentNestLists.slice(nestListIndex + 1);
|
|
192
|
+
ancestorPath.push({ list: grandParentList, ancestorIndex, trailingNestLists });
|
|
193
|
+
currentList = grandParentList;
|
|
194
|
+
}
|
|
195
|
+
// currentList is now the root-level list
|
|
196
|
+
const rootList = currentList;
|
|
197
|
+
const rootContainer = rootList.parent;
|
|
198
|
+
const trailingGroups = [];
|
|
199
|
+
// 1. Trailing items from the target nested list (same type as target)
|
|
200
|
+
if (nestedTrailingItems.length > 0) {
|
|
201
|
+
trailingGroups.push({ items: nestedTrailingItems, sourceList: target });
|
|
202
|
+
}
|
|
203
|
+
// 2. Trailing nestLists from ancestors (innermost to outermost)
|
|
204
|
+
// 3. Trailing items from each ancestor level's list
|
|
205
|
+
for (const level of ancestorPath) {
|
|
206
|
+
// Trailing nestLists from the ancestor item
|
|
207
|
+
for (const trailingNest of level.trailingNestLists) {
|
|
208
|
+
if (trailingNest.children.length > 0) {
|
|
209
|
+
trailingGroups.push({ items: [...trailingNest.children], sourceList: trailingNest });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Trailing items from ancestor's list (items after the ancestor item)
|
|
213
|
+
const trailingFromLevel = level.list.children.slice(level.ancestorIndex + 1);
|
|
214
|
+
if (trailingFromLevel.length > 0) {
|
|
215
|
+
trailingGroups.push({ items: trailingFromLevel, sourceList: level.list });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Merge only groups whose list type and container annotations match. Different
|
|
219
|
+
// class/style/attribute boundaries must survive the structural reconstruction.
|
|
220
|
+
const mergedGroups = [];
|
|
221
|
+
for (const group of trailingGroups) {
|
|
222
|
+
const prev = mergedGroups[mergedGroups.length - 1];
|
|
223
|
+
if (prev &&
|
|
224
|
+
prev.sourceList.type === group.sourceList.type &&
|
|
225
|
+
this.haveSameListAnnotations(prev.sourceList, group.sourceList)) {
|
|
226
|
+
prev.items.push(...group.items);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
mergedGroups.push({ items: [...group.items], sourceList: group.sourceList });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Build the "after" lists
|
|
233
|
+
const afterLists = mergedGroups.map((group) => {
|
|
234
|
+
const newList = this.createListFromSource(rootContent, group.sourceList);
|
|
235
|
+
newList.apply(new AppendChildrenAction(group.items));
|
|
236
|
+
return newList;
|
|
237
|
+
});
|
|
238
|
+
afterLists.forEach((list) => this.appendListBlock(insertions, list));
|
|
239
|
+
// --- Now trim the "before" portion ---
|
|
240
|
+
// Trim target nested list: keep only items before selected
|
|
241
|
+
target.children = target.children.slice(0, selectedIndex);
|
|
242
|
+
// Clean up the target nested list's parent item's nestList
|
|
243
|
+
const targetParentItem = target.parent;
|
|
244
|
+
const targetParentNestLists = targetParentItem.nestList;
|
|
245
|
+
const targetNestIndex = targetParentNestLists.indexOf(target);
|
|
246
|
+
// Keep only nestLists up to and including the target (remove trailing ones we already collected)
|
|
247
|
+
let trimmedNestList = targetParentNestLists.slice(0, targetNestIndex + 1);
|
|
248
|
+
// If target is now empty, remove it too
|
|
249
|
+
if (target.children.length === 0) {
|
|
250
|
+
trimmedNestList = trimmedNestList.filter((l) => l !== target);
|
|
251
|
+
}
|
|
252
|
+
targetParentItem.apply(new ReplaceNestListAction(trimmedNestList));
|
|
253
|
+
// Trim ancestor levels: remove trailing items and trailing nestLists
|
|
254
|
+
for (const level of ancestorPath) {
|
|
255
|
+
// Remove trailing items from the ancestor's list
|
|
256
|
+
level.list.children = level.list.children.slice(0, level.ancestorIndex + 1);
|
|
257
|
+
// Remove trailing nestLists from the ancestor item
|
|
258
|
+
if (level.trailingNestLists.length > 0) {
|
|
259
|
+
const ancestorItem = level.list.children[level.ancestorIndex];
|
|
260
|
+
const ancestorNestLists = ancestorItem.nestList;
|
|
261
|
+
const firstTrailingNestIndex = ancestorNestLists.indexOf(level.trailingNestLists[0]);
|
|
262
|
+
if (firstTrailingNestIndex >= 0) {
|
|
263
|
+
const keptNestLists = ancestorNestLists.slice(0, firstTrailingNestIndex);
|
|
264
|
+
ancestorItem.apply(new ReplaceNestListAction(keptNestLists));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
rootContainer.apply(new InsertChildrenAfterAction(rootList, ...insertions));
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Normalize selected items into document order and split them into contiguous
|
|
272
|
+
* segments that share the same immediate parent list. Unlike Shift+Tab, the
|
|
273
|
+
* toolbar action keeps selected descendants so every selected item becomes a
|
|
274
|
+
* paragraph.
|
|
275
|
+
*
|
|
276
|
+
* @param {RTEBlock[]} selectedBlocks - Raw selected blocks.
|
|
277
|
+
* @returns {RTEListItemBlock[][]} Parent-based contiguous selection segments.
|
|
278
|
+
*/
|
|
279
|
+
getSelectedSegments(selectedBlocks) {
|
|
280
|
+
const selectedItems = Array.from(new Set(selectedBlocks.filter((block) => block instanceof RTEListItemBlock)))
|
|
281
|
+
.map((item) => ({ item, path: this.getStructuralPath(item) }))
|
|
282
|
+
.filter((entry) => entry.path !== null)
|
|
283
|
+
.sort((a, b) => this.compareStructuralPaths(a.path, b.path))
|
|
284
|
+
.map((entry) => entry.item);
|
|
285
|
+
const segments = [];
|
|
286
|
+
for (const item of selectedItems) {
|
|
287
|
+
const segment = segments[segments.length - 1];
|
|
288
|
+
const previousItem = segment === null || segment === void 0 ? void 0 : segment[segment.length - 1];
|
|
289
|
+
const isContiguousSibling = (previousItem === null || previousItem === void 0 ? void 0 : previousItem.parent) === item.parent &&
|
|
290
|
+
item.parent.children.indexOf(item) - item.parent.children.indexOf(previousItem) === 1;
|
|
291
|
+
if (isContiguousSibling) {
|
|
292
|
+
segment.push(item);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
segments.push([item]);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return segments;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Resolve a list item's structural document path, including the positions of
|
|
302
|
+
* root lists, owning list items, nested lists, and the item itself.
|
|
303
|
+
*
|
|
304
|
+
* @param {RTEListItemBlock} item - Selected list item.
|
|
305
|
+
* @returns {number[] | null} Structural path, or null for a detached item.
|
|
306
|
+
*/
|
|
307
|
+
getStructuralPath(item) {
|
|
308
|
+
var _a;
|
|
309
|
+
const path = [];
|
|
310
|
+
const visitedLists = new Set();
|
|
311
|
+
let currentItem = item;
|
|
312
|
+
let currentList = item.parent;
|
|
313
|
+
while (!visitedLists.has(currentList)) {
|
|
314
|
+
visitedLists.add(currentList);
|
|
315
|
+
const itemIndex = currentList.children.indexOf(currentItem);
|
|
316
|
+
if (itemIndex < 0) {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
path.unshift(itemIndex);
|
|
320
|
+
if (currentList.parent.dtoName === 'VegaRTEContent' ||
|
|
321
|
+
currentList.parent.dtoName === 'RTEHtmlBlock') {
|
|
322
|
+
const containerPath = this.getContainerPath(currentList);
|
|
323
|
+
return containerPath ? [...containerPath, ...path] : null;
|
|
324
|
+
}
|
|
325
|
+
if (!(currentList.parent instanceof RTEListItemBlock)) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
const ownerItem = currentList.parent;
|
|
329
|
+
const nestListIndex = ((_a = ownerItem.nestList) !== null && _a !== void 0 ? _a : []).indexOf(currentList);
|
|
330
|
+
if (nestListIndex < 0) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
path.unshift(nestListIndex);
|
|
334
|
+
currentItem = ownerItem;
|
|
335
|
+
currentList = ownerItem.parent;
|
|
336
|
+
}
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Resolve a root list's path through zero or more HTML containers to the
|
|
341
|
+
* editor content.
|
|
342
|
+
*
|
|
343
|
+
* @param {RTEListBlock} rootList - List whose parent is a content container.
|
|
344
|
+
* @returns {number[] | null} Container path, or null for detached/cyclic ownership.
|
|
345
|
+
*/
|
|
346
|
+
getContainerPath(rootList) {
|
|
347
|
+
const path = [];
|
|
348
|
+
const visitedContainers = new Set();
|
|
349
|
+
let child = rootList;
|
|
350
|
+
let container = rootList.parent;
|
|
351
|
+
while (container instanceof RTEHtmlBlock) {
|
|
352
|
+
if (visitedContainers.has(container)) {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
visitedContainers.add(container);
|
|
356
|
+
const childIndex = container.children.indexOf(child);
|
|
357
|
+
if (childIndex < 0) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
path.unshift(childIndex);
|
|
361
|
+
child = container;
|
|
362
|
+
container = container.parent;
|
|
363
|
+
}
|
|
364
|
+
const rootChildIndex = container.children.indexOf(child);
|
|
365
|
+
if (rootChildIndex < 0) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
path.unshift(rootChildIndex);
|
|
369
|
+
return path;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Compare two structural paths in document order.
|
|
373
|
+
*
|
|
374
|
+
* @param {number[]} firstPath - First structural path.
|
|
375
|
+
* @param {number[]} secondPath - Second structural path.
|
|
376
|
+
* @returns {number} Relative document order.
|
|
377
|
+
*/
|
|
378
|
+
compareStructuralPaths(firstPath, secondPath) {
|
|
379
|
+
const length = Math.min(firstPath.length, secondPath.length);
|
|
380
|
+
for (let index = 0; index < length; index++) {
|
|
381
|
+
if (firstPath[index] !== secondPath[index]) {
|
|
382
|
+
return firstPath[index] - secondPath[index];
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return firstPath.length - secondPath.length;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Append a list to an operation-local block sequence, merging only with the
|
|
389
|
+
* immediately preceding same-type list in that sequence.
|
|
390
|
+
*
|
|
391
|
+
* @param {RTEBlock[]} blocks - Operation-local output sequence.
|
|
392
|
+
* @param {RTEListBlock} list - List to append or merge.
|
|
393
|
+
*/
|
|
394
|
+
appendListBlock(blocks, list) {
|
|
395
|
+
const previousBlock = blocks[blocks.length - 1];
|
|
396
|
+
if (previousBlock instanceof RTEListBlock &&
|
|
397
|
+
previousBlock.type === list.type &&
|
|
398
|
+
this.haveSameListAnnotations(previousBlock, list)) {
|
|
399
|
+
previousBlock.apply(new AppendChildrenAction([...list.children]));
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
blocks.push(list);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Create a list through the content factory and retain the source list's
|
|
406
|
+
* container annotations when a structural split requires a new list block.
|
|
407
|
+
*
|
|
408
|
+
* @param {VegaRTEContent} rootContent - Editor content that owns the factory.
|
|
409
|
+
* @param {RTEListBlock} source - List whose type and annotations should be retained.
|
|
410
|
+
* @returns {RTEListBlock} Newly created list shell.
|
|
411
|
+
*/
|
|
412
|
+
createListFromSource(rootContent, source) {
|
|
413
|
+
const list = rootContent.createList(source.type);
|
|
414
|
+
this.copyListAnnotations(source, list);
|
|
415
|
+
return list;
|
|
50
416
|
}
|
|
51
417
|
/**
|
|
52
418
|
* Converts a RTEListItemBlock to a RTETextBlock representing a paragraph.
|