astro-tractstack 2.2.2 → 2.2.4
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/package.json +1 -1
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +0 -1
- package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +0 -1
- package/templates/src/components/codehooks/ListContentSetup.tsx +0 -1
- package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -1
- package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -1
- package/templates/src/components/compositor/Compositor.tsx +0 -1
- package/templates/src/components/compositor/Node.tsx +157 -134
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +2 -4
- package/templates/src/components/edit/Header.tsx +1 -2
- package/templates/src/components/edit/context/ContextPaneConfig_slug.tsx +1 -1
- package/templates/src/components/edit/context/ContextPaneConfig_title.tsx +0 -1
- package/templates/src/components/edit/pane/AddPanePanel_break.tsx +1 -0
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +8 -12
- package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +9 -6
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +2 -2
- package/templates/src/components/edit/pane/PanePanel_impression.tsx +0 -4
- package/templates/src/components/edit/pane/PanePanel_path.tsx +0 -1
- package/templates/src/components/edit/pane/PanePanel_title.tsx +1 -2
- package/templates/src/components/edit/pane/RestylePaneModal.tsx +1 -4
- package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +0 -3
- package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +2 -2
- package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +173 -80
- package/templates/src/components/edit/pane/steps/CreativeInjectStep.tsx +0 -5
- package/templates/src/components/edit/pane/steps/DesignLibraryStep.tsx +2 -1
- package/templates/src/components/edit/panels/StyleBreakPanel.tsx +1 -4
- package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +0 -1
- package/templates/src/components/edit/panels/StyleElementPanel.tsx +1 -1
- package/templates/src/components/edit/panels/StyleElementPanel_remove.tsx +1 -4
- package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +3 -3
- package/templates/src/components/edit/panels/StyleImagePanel.tsx +3 -3
- package/templates/src/components/edit/panels/StyleImagePanel_remove.tsx +1 -4
- package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +3 -4
- package/templates/src/components/edit/panels/StyleLiElementPanel_remove.tsx +1 -4
- package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +3 -3
- package/templates/src/components/edit/panels/StyleLinkPanel.tsx +1 -1
- package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +1 -1
- package/templates/src/components/edit/panels/StyleLinkPanel_remove.tsx +1 -1
- package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +1 -1
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +0 -7
- package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +0 -2
- package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +0 -2
- package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +0 -2
- package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +0 -3
- package/templates/src/components/edit/panels/StyleWidgetPanel_remove.tsx +1 -4
- package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +3 -4
- package/templates/src/components/edit/panels/StyleWordCarouselPanel.tsx +0 -2
- package/templates/src/components/edit/state/StylesMemory.tsx +3 -9
- package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +0 -1
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +0 -2
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +0 -2
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +0 -1
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_title.tsx +0 -1
- package/templates/src/components/fields/ArtpackImage.tsx +0 -7
- package/templates/src/components/fields/BackgroundImage.tsx +0 -14
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +0 -5
- package/templates/src/components/fields/ImageUpload.tsx +0 -3
- package/templates/src/pages/[...slug]/edit.astro +0 -1
- package/templates/src/pages/api/auth/logout.ts +9 -20
- package/templates/src/pages/sandbox.astro +0 -1
- package/templates/src/stores/nodes.ts +278 -312
- package/templates/src/stores/nodesHistory.ts +59 -24
- package/templates/src/utils/api/setupHelpers.ts +1 -1
- package/templates/src/utils/compositor/aiPaneParser.ts +57 -0
- package/templates/src/utils/compositor/designLibraryHelper.ts +1 -3
- package/templates/src/utils/compositor/htmlAst.ts +109 -2
- package/templates/src/utils/compositor/nodesHelper.ts +1 -9
- package/templates/src/utils/compositor/savePipeline.ts +1 -4
|
@@ -7,7 +7,11 @@ import { extractClassesFromNodes } from '@/utils/compositor/nodesHelper';
|
|
|
7
7
|
import { handleClickEventDefault } from '@/utils/compositor/handleClickEvent';
|
|
8
8
|
import allowInsert from '@/utils/compositor/allowInsert';
|
|
9
9
|
import { reservedSlugs } from '@/constants';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
NodesHistory,
|
|
12
|
+
PatchOp,
|
|
13
|
+
VERBOSE as VERBOSE_HISTORY,
|
|
14
|
+
} from '@/stores/nodesHistory';
|
|
11
15
|
import { moveNodeAtLocationInContext } from '@/utils/compositor/nodesHelper';
|
|
12
16
|
import {
|
|
13
17
|
rehydrateChildrenFromHtml,
|
|
@@ -90,7 +94,6 @@ export class NodesContext {
|
|
|
90
94
|
allNodes = atom<Map<string, BaseNode>>(new Map<string, BaseNode>());
|
|
91
95
|
impressionNodes = atom<Set<ImpressionNode>>(new Set<ImpressionNode>());
|
|
92
96
|
parentNodes = atom<Map<string, string[]>>(new Map<string, string[]>());
|
|
93
|
-
showSaveBypass = atom<boolean>(false);
|
|
94
97
|
hasTitle = atom<boolean>(false);
|
|
95
98
|
hasPanes = atom<boolean>(false);
|
|
96
99
|
isTemplate = atom<boolean>(false);
|
|
@@ -257,24 +260,6 @@ export class NodesContext {
|
|
|
257
260
|
});
|
|
258
261
|
}
|
|
259
262
|
|
|
260
|
-
//setActiveGhost(nodeId: string): void {
|
|
261
|
-
// const currentActiveId = this.ghostTextActiveId.get();
|
|
262
|
-
// // If this is already the active ghost, do nothing
|
|
263
|
-
// if (currentActiveId === nodeId) return;
|
|
264
|
-
// // If another ghost is active, clear it first
|
|
265
|
-
// if (currentActiveId && currentActiveId !== nodeId) {
|
|
266
|
-
// // Set to empty string to close any existing ghost
|
|
267
|
-
// this.ghostTextActiveId.set("");
|
|
268
|
-
// // After a short delay to allow the previous ghost to close,
|
|
269
|
-
// // set the new active ghost
|
|
270
|
-
// setTimeout(() => {
|
|
271
|
-
// this.ghostTextActiveId.set(nodeId);
|
|
272
|
-
// }, 100);
|
|
273
|
-
// } else {
|
|
274
|
-
// this.ghostTextActiveId.set(nodeId);
|
|
275
|
-
// }
|
|
276
|
-
//}
|
|
277
|
-
|
|
278
263
|
updateHasPanesStatus() {
|
|
279
264
|
const allNodes = this.allNodes.get();
|
|
280
265
|
const storyFragments = Array.from(allNodes.values()).filter(
|
|
@@ -328,7 +313,7 @@ export class NodesContext {
|
|
|
328
313
|
const storyfragmentNode = cloneDeep(
|
|
329
314
|
this.allNodes.get().get(storyfragmentNodeId)
|
|
330
315
|
) as StoryFragmentNode;
|
|
331
|
-
this.modifyNodes([{ ...storyfragmentNode
|
|
316
|
+
this.modifyNodes([{ ...storyfragmentNode }]);
|
|
332
317
|
break;
|
|
333
318
|
}
|
|
334
319
|
case `TagElement`: {
|
|
@@ -336,7 +321,7 @@ export class NodesContext {
|
|
|
336
321
|
const paneNode = cloneDeep(
|
|
337
322
|
this.allNodes.get().get(paneNodeId)
|
|
338
323
|
) as PaneNode;
|
|
339
|
-
this.modifyNodes([{ ...paneNode
|
|
324
|
+
this.modifyNodes([{ ...paneNode }]);
|
|
340
325
|
break;
|
|
341
326
|
}
|
|
342
327
|
default:
|
|
@@ -517,7 +502,7 @@ export class NodesContext {
|
|
|
517
502
|
this.parentNodes.set(newParentNodes);
|
|
518
503
|
|
|
519
504
|
if (originalPaneNode) {
|
|
520
|
-
this.modifyNodes([{ ...originalPaneNode
|
|
505
|
+
this.modifyNodes([{ ...originalPaneNode }], {
|
|
521
506
|
notify: false,
|
|
522
507
|
recordHistory: false,
|
|
523
508
|
});
|
|
@@ -542,11 +527,15 @@ export class NodesContext {
|
|
|
542
527
|
|
|
543
528
|
const newAnchorId = redoLogic();
|
|
544
529
|
|
|
545
|
-
this.
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
530
|
+
if (!this.isTemplate.get()) {
|
|
531
|
+
if (VERBOSE_HISTORY)
|
|
532
|
+
console.log('[Nodes] Action: wrapRangeInAnchor', { range });
|
|
533
|
+
this.history.addPatch({
|
|
534
|
+
op: PatchOp.REPLACE,
|
|
535
|
+
undo: undoLogic,
|
|
536
|
+
redo: redoLogic,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
550
539
|
|
|
551
540
|
return new Promise((resolve) =>
|
|
552
541
|
setTimeout(() => resolve(newAnchorId), 310)
|
|
@@ -554,31 +543,29 @@ export class NodesContext {
|
|
|
554
543
|
}
|
|
555
544
|
|
|
556
545
|
applyShellToPane(paneId: string, template: TemplatePane) {
|
|
557
|
-
const
|
|
558
|
-
const originalPane =
|
|
546
|
+
const allNodesMap = this.allNodes.get();
|
|
547
|
+
const originalPane = allNodesMap.get(paneId);
|
|
559
548
|
if (!originalPane) return;
|
|
560
549
|
|
|
561
|
-
const
|
|
562
|
-
paneNode.isChanged = true;
|
|
550
|
+
const nodesToUpdate: BaseNode[] = [];
|
|
563
551
|
|
|
552
|
+
const paneNode = cloneDeep(originalPane) as PaneNode;
|
|
564
553
|
if (template.bgColour) {
|
|
565
554
|
paneNode.bgColour = template.bgColour;
|
|
566
555
|
}
|
|
567
556
|
if (template.htmlAst) {
|
|
568
557
|
paneNode.htmlAst = template.htmlAst;
|
|
569
558
|
}
|
|
570
|
-
|
|
571
|
-
allNodes.set(paneId, paneNode);
|
|
559
|
+
nodesToUpdate.push(paneNode);
|
|
572
560
|
|
|
573
561
|
const childrenIds = this.getChildNodeIDs(paneId);
|
|
574
562
|
|
|
575
563
|
const gridNodeRaw = childrenIds
|
|
576
|
-
.map((id) =>
|
|
564
|
+
.map((id) => allNodesMap.get(id))
|
|
577
565
|
.find((n) => n?.nodeType === 'GridLayoutNode');
|
|
578
566
|
|
|
579
567
|
if (gridNodeRaw && template.gridLayout) {
|
|
580
568
|
const gridLayoutNode = cloneDeep(gridNodeRaw) as GridLayoutNode;
|
|
581
|
-
gridLayoutNode.isChanged = true;
|
|
582
569
|
|
|
583
570
|
if (template.gridLayout.parentClasses) {
|
|
584
571
|
gridLayoutNode.parentClasses = template.gridLayout.parentClasses;
|
|
@@ -586,7 +573,7 @@ export class NodesContext {
|
|
|
586
573
|
if (template.gridLayout.defaultClasses) {
|
|
587
574
|
gridLayoutNode.defaultClasses = template.gridLayout.defaultClasses;
|
|
588
575
|
}
|
|
589
|
-
|
|
576
|
+
nodesToUpdate.push(gridLayoutNode);
|
|
590
577
|
|
|
591
578
|
if (
|
|
592
579
|
template.gridLayout.nodes &&
|
|
@@ -596,27 +583,25 @@ export class NodesContext {
|
|
|
596
583
|
|
|
597
584
|
columnIds.forEach((colId, index) => {
|
|
598
585
|
const templateCol = template.gridLayout!.nodes![index];
|
|
599
|
-
const colNodeRaw =
|
|
586
|
+
const colNodeRaw = allNodesMap.get(colId);
|
|
600
587
|
if (templateCol && colNodeRaw) {
|
|
601
588
|
const liveColNode = cloneDeep(
|
|
602
589
|
colNodeRaw
|
|
603
590
|
) as MarkdownPaneFragmentNode;
|
|
604
591
|
liveColNode.gridClasses = templateCol.gridClasses;
|
|
605
|
-
liveColNode
|
|
606
|
-
allNodes.set(colId, liveColNode);
|
|
592
|
+
nodesToUpdate.push(liveColNode);
|
|
607
593
|
}
|
|
608
594
|
});
|
|
609
595
|
}
|
|
610
596
|
} else {
|
|
611
597
|
const markdownNodes = childrenIds
|
|
612
|
-
.map((id) =>
|
|
598
|
+
.map((id) => allNodesMap.get(id))
|
|
613
599
|
.filter(
|
|
614
600
|
(n) => n?.nodeType === 'Markdown'
|
|
615
601
|
) as MarkdownPaneFragmentNode[];
|
|
616
602
|
|
|
617
603
|
if (markdownNodes.length > 0 && template.markdown) {
|
|
618
604
|
const primaryMarkdown = cloneDeep(markdownNodes[0]);
|
|
619
|
-
primaryMarkdown.isChanged = true;
|
|
620
605
|
|
|
621
606
|
if (template.markdown.parentClasses) {
|
|
622
607
|
primaryMarkdown.parentClasses = template.markdown.parentClasses;
|
|
@@ -624,14 +609,12 @@ export class NodesContext {
|
|
|
624
609
|
if (template.markdown.defaultClasses) {
|
|
625
610
|
primaryMarkdown.defaultClasses = template.markdown.defaultClasses;
|
|
626
611
|
}
|
|
627
|
-
|
|
612
|
+
nodesToUpdate.push(primaryMarkdown);
|
|
628
613
|
}
|
|
629
614
|
}
|
|
630
615
|
|
|
631
|
-
this
|
|
632
|
-
this.
|
|
633
|
-
this.notifyNode('root');
|
|
634
|
-
this.showSaveBypass.set(true);
|
|
616
|
+
// Force a fresh history entry for this operation
|
|
617
|
+
this.modifyNodes(nodesToUpdate, { merge: false });
|
|
635
618
|
}
|
|
636
619
|
|
|
637
620
|
async updateCreativeAsset(
|
|
@@ -681,28 +664,19 @@ export class NodesContext {
|
|
|
681
664
|
}
|
|
682
665
|
|
|
683
666
|
paneNode.htmlAst = newHtmlAst;
|
|
684
|
-
paneNode.isChanged = true;
|
|
685
667
|
|
|
686
668
|
this.modifyNodes([paneNode]);
|
|
687
669
|
}
|
|
688
670
|
|
|
689
671
|
updateCreativePane(paneId: string, containerId: string, htmlContent: string) {
|
|
690
|
-
const
|
|
691
|
-
const originalPane = allNodes.get(paneId);
|
|
692
|
-
|
|
693
|
-
// 1. Validation and Clone (matching applyShellToPane pattern)
|
|
672
|
+
const originalPane = this.allNodes.get().get(paneId);
|
|
694
673
|
if (!originalPane || originalPane.nodeType !== 'Pane') return;
|
|
695
674
|
|
|
696
|
-
// Deep clone ensures we don't mutate state outside the atom update
|
|
697
675
|
const paneNode = cloneDeep(originalPane) as PaneNode;
|
|
698
|
-
|
|
699
|
-
// Guard: Ensure we are in HTML mode
|
|
700
676
|
if (!('htmlAst' in paneNode) || !paneNode.htmlAst) return;
|
|
701
677
|
|
|
702
|
-
// 2. Logic: Rehydrate and Patch
|
|
703
678
|
const newChildren = rehydrateChildrenFromHtml(htmlContent);
|
|
704
679
|
|
|
705
|
-
// Recursive patcher to find the container in the cloned tree
|
|
706
680
|
const patchNode = (nodes: any[]): boolean => {
|
|
707
681
|
for (const node of nodes) {
|
|
708
682
|
if (node.id === containerId) {
|
|
@@ -716,13 +690,8 @@ export class NodesContext {
|
|
|
716
690
|
return false;
|
|
717
691
|
};
|
|
718
692
|
|
|
719
|
-
// 3. Commit
|
|
720
693
|
if (patchNode(paneNode.htmlAst.tree)) {
|
|
721
|
-
paneNode
|
|
722
|
-
allNodes.set(paneId, paneNode);
|
|
723
|
-
this.allNodes.set(allNodes);
|
|
724
|
-
this.notifyNode(paneId);
|
|
725
|
-
this.showSaveBypass.set(true);
|
|
694
|
+
this.modifyNodes([paneNode], { merge: false });
|
|
726
695
|
}
|
|
727
696
|
}
|
|
728
697
|
|
|
@@ -905,8 +874,6 @@ export class NodesContext {
|
|
|
905
874
|
* @param tagName - The tag name for the wrapper element (e.g., 'span').
|
|
906
875
|
* @returns A Promise that resolves with the new wrapper node's ID, or null.
|
|
907
876
|
*/
|
|
908
|
-
// Replacement for wrapRangeInSpan in src/stores/nodes.ts
|
|
909
|
-
|
|
910
877
|
public async wrapRangeInSpan(
|
|
911
878
|
range: SelectionRange,
|
|
912
879
|
tagName: 'span'
|
|
@@ -1072,7 +1039,7 @@ export class NodesContext {
|
|
|
1072
1039
|
this.parentNodes.set(newParentNodes);
|
|
1073
1040
|
|
|
1074
1041
|
if (originalPaneNode) {
|
|
1075
|
-
this.modifyNodes([{ ...originalPaneNode
|
|
1042
|
+
this.modifyNodes([{ ...originalPaneNode }], {
|
|
1076
1043
|
notify: false,
|
|
1077
1044
|
recordHistory: false,
|
|
1078
1045
|
});
|
|
@@ -1116,11 +1083,15 @@ export class NodesContext {
|
|
|
1116
1083
|
|
|
1117
1084
|
const newSpanId = redoLogic();
|
|
1118
1085
|
|
|
1119
|
-
this.
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1086
|
+
if (!this.isTemplate.get()) {
|
|
1087
|
+
if (VERBOSE_HISTORY)
|
|
1088
|
+
console.log('[Nodes] Action: wrapRangeInSpan', { range, tagName });
|
|
1089
|
+
this.history.addPatch({
|
|
1090
|
+
op: PatchOp.REPLACE,
|
|
1091
|
+
undo: undoLogic,
|
|
1092
|
+
redo: redoLogic,
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1124
1095
|
|
|
1125
1096
|
return new Promise((resolve) => setTimeout(() => resolve(newSpanId), 310));
|
|
1126
1097
|
}
|
|
@@ -1742,37 +1713,33 @@ export class NodesContext {
|
|
|
1742
1713
|
options?: {
|
|
1743
1714
|
notify?: boolean;
|
|
1744
1715
|
recordHistory?: boolean;
|
|
1716
|
+
merge?: boolean;
|
|
1745
1717
|
}
|
|
1746
1718
|
) {
|
|
1747
1719
|
const undoList: ((ctx: NodesContext) => void)[] = [];
|
|
1748
1720
|
const redoList: ((ctx: NodesContext) => void)[] = [];
|
|
1749
1721
|
const shouldNotify = options?.notify ?? true;
|
|
1750
|
-
const shouldRecordHistory =
|
|
1722
|
+
const shouldRecordHistory =
|
|
1723
|
+
(options?.recordHistory ?? true) && !this.isTemplate.get();
|
|
1724
|
+
|
|
1725
|
+
for (const incomingNode of newData) {
|
|
1726
|
+
// Centralized persistence flag: Always mark modified nodes as changed
|
|
1727
|
+
const node = { ...incomingNode, isChanged: true };
|
|
1751
1728
|
|
|
1752
|
-
for (let i = 0; i < newData.length; i++) {
|
|
1753
|
-
const node = newData[i];
|
|
1754
1729
|
const currentNodeData = this.allNodes.get().get(node.id) as BaseNode;
|
|
1755
|
-
if (!currentNodeData)
|
|
1756
|
-
|
|
1757
|
-
|
|
1730
|
+
if (!currentNodeData) continue;
|
|
1731
|
+
|
|
1732
|
+
if (isDeepEqual(currentNodeData, node)) continue;
|
|
1758
1733
|
|
|
1759
|
-
if (
|
|
1760
|
-
|
|
1734
|
+
if (VERBOSE_HISTORY) {
|
|
1735
|
+
console.log(`[Nodes] Modifying ${node.nodeType} (${node.id})`, node);
|
|
1761
1736
|
}
|
|
1762
1737
|
|
|
1763
1738
|
const newNodes = new Map(this.allNodes.get());
|
|
1764
1739
|
newNodes.set(node.id, node);
|
|
1765
1740
|
this.allNodes.set(newNodes);
|
|
1766
1741
|
|
|
1767
|
-
|
|
1768
|
-
'isChanged',
|
|
1769
|
-
]);
|
|
1770
|
-
|
|
1771
|
-
if (deepEqualWithExclusions) {
|
|
1772
|
-
if (shouldNotify) this.notifyNode(node.id);
|
|
1773
|
-
continue;
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1742
|
+
// Check if we need to dirty parents (bubbling changes up)
|
|
1776
1743
|
switch (node.nodeType) {
|
|
1777
1744
|
case 'GridLayoutNode':
|
|
1778
1745
|
case 'TagElement':
|
|
@@ -1784,7 +1751,7 @@ export class NodesContext {
|
|
|
1784
1751
|
if (paneNodeId) {
|
|
1785
1752
|
const paneNode = this.allNodes.get().get(paneNodeId);
|
|
1786
1753
|
if (paneNode && !paneNode.isChanged) {
|
|
1787
|
-
nodesToDirty.push({ ...paneNode
|
|
1754
|
+
nodesToDirty.push({ ...paneNode });
|
|
1788
1755
|
}
|
|
1789
1756
|
}
|
|
1790
1757
|
|
|
@@ -1796,7 +1763,7 @@ export class NodesContext {
|
|
|
1796
1763
|
!parentNode.isChanged
|
|
1797
1764
|
) {
|
|
1798
1765
|
if (!nodesToDirty.some((n) => n.id === parentNode.id)) {
|
|
1799
|
-
nodesToDirty.push({ ...parentNode
|
|
1766
|
+
nodesToDirty.push({ ...parentNode });
|
|
1800
1767
|
}
|
|
1801
1768
|
}
|
|
1802
1769
|
}
|
|
@@ -1807,18 +1774,8 @@ export class NodesContext {
|
|
|
1807
1774
|
recordHistory: false,
|
|
1808
1775
|
});
|
|
1809
1776
|
}
|
|
1810
|
-
|
|
1811
|
-
this.notifyNode(ROOT_NODE_NAME);
|
|
1812
1777
|
break;
|
|
1813
1778
|
}
|
|
1814
|
-
|
|
1815
|
-
case `Menu`:
|
|
1816
|
-
case `Pane`:
|
|
1817
|
-
case `StoryFragment`:
|
|
1818
|
-
break;
|
|
1819
|
-
|
|
1820
|
-
default:
|
|
1821
|
-
console.warn(`must dirty check missed on `, node.nodeType);
|
|
1822
1779
|
}
|
|
1823
1780
|
|
|
1824
1781
|
undoList.push((ctx: NodesContext) => {
|
|
@@ -1826,8 +1783,7 @@ export class NodesContext {
|
|
|
1826
1783
|
newNodes.set(node.id, currentNodeData);
|
|
1827
1784
|
ctx.allNodes.set(newNodes);
|
|
1828
1785
|
if (shouldNotify) {
|
|
1829
|
-
|
|
1830
|
-
if (parentNode) this.notifyNode(parentNode);
|
|
1786
|
+
ctx.notifyNode(node.id);
|
|
1831
1787
|
}
|
|
1832
1788
|
});
|
|
1833
1789
|
redoList.push((ctx: NodesContext) => {
|
|
@@ -1835,28 +1791,32 @@ export class NodesContext {
|
|
|
1835
1791
|
newNodes.set(node.id, node);
|
|
1836
1792
|
ctx.allNodes.set(newNodes);
|
|
1837
1793
|
if (shouldNotify) {
|
|
1838
|
-
|
|
1839
|
-
if (parentNode) this.notifyNode(parentNode);
|
|
1794
|
+
ctx.notifyNode(node.id);
|
|
1840
1795
|
}
|
|
1841
1796
|
});
|
|
1842
1797
|
|
|
1843
1798
|
if (shouldNotify) {
|
|
1844
|
-
if ([`Menu`, `StoryFragment`].includes(node.nodeType))
|
|
1845
|
-
this.notifyNode(ROOT_NODE_NAME);
|
|
1846
1799
|
this.notifyNode(node.id);
|
|
1800
|
+
const parentNodeToNotify = this.nodeToNotify(node.id, node.nodeType);
|
|
1801
|
+
if (parentNodeToNotify && parentNodeToNotify !== node.id) {
|
|
1802
|
+
this.notifyNode(parentNodeToNotify);
|
|
1803
|
+
} else this.notifyNode('root');
|
|
1847
1804
|
}
|
|
1848
1805
|
}
|
|
1849
1806
|
|
|
1850
1807
|
if (undoList.length > 0 && shouldRecordHistory) {
|
|
1851
|
-
this.history.addPatch(
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1808
|
+
this.history.addPatch(
|
|
1809
|
+
{
|
|
1810
|
+
op: PatchOp.REPLACE,
|
|
1811
|
+
undo: (ctx) => {
|
|
1812
|
+
undoList.forEach((fn) => fn(ctx));
|
|
1813
|
+
},
|
|
1814
|
+
redo: (ctx) => {
|
|
1815
|
+
redoList.forEach((fn) => fn(ctx));
|
|
1816
|
+
},
|
|
1858
1817
|
},
|
|
1859
|
-
|
|
1818
|
+
{ merge: options?.merge }
|
|
1819
|
+
);
|
|
1860
1820
|
}
|
|
1861
1821
|
}
|
|
1862
1822
|
|
|
@@ -1915,7 +1875,6 @@ export class NodesContext {
|
|
|
1915
1875
|
duplicatedPane.title = ownerNode.title;
|
|
1916
1876
|
if (ownerNode && 'slug' in ownerNode && typeof ownerNode.slug === `string`)
|
|
1917
1877
|
duplicatedPane.slug = ownerNode.slug;
|
|
1918
|
-
duplicatedPane.isChanged = true;
|
|
1919
1878
|
|
|
1920
1879
|
// Track all nodes that need to be added
|
|
1921
1880
|
// Call the new helper to process markdown, gridLayout, and bgPane
|
|
@@ -1960,7 +1919,6 @@ export class NodesContext {
|
|
|
1960
1919
|
const duplicatedPaneId = pane?.id || ulid();
|
|
1961
1920
|
duplicatedPane.id = duplicatedPaneId;
|
|
1962
1921
|
duplicatedPane.parentId = ownerNode.id;
|
|
1963
|
-
duplicatedPane.isChanged = true;
|
|
1964
1922
|
|
|
1965
1923
|
if (this.rootNodeId.get() !== 'tmp') {
|
|
1966
1924
|
if (
|
|
@@ -2002,7 +1960,6 @@ export class NodesContext {
|
|
|
2002
1960
|
location &&
|
|
2003
1961
|
storyFragmentNode?.nodeType === 'StoryFragment'
|
|
2004
1962
|
) {
|
|
2005
|
-
storyFragmentWasChanged = storyFragmentNode.isChanged || false;
|
|
2006
1963
|
specificIdx = storyFragmentNode.paneIds.indexOf(insertPaneId);
|
|
2007
1964
|
elIdx = specificIdx;
|
|
2008
1965
|
if (elIdx === -1) {
|
|
@@ -2019,7 +1976,6 @@ export class NodesContext {
|
|
|
2019
1976
|
);
|
|
2020
1977
|
}
|
|
2021
1978
|
}
|
|
2022
|
-
storyFragmentNode.isChanged = true;
|
|
2023
1979
|
}
|
|
2024
1980
|
|
|
2025
1981
|
this.addNode(duplicatedPane as PaneNode);
|
|
@@ -2034,46 +1990,55 @@ export class NodesContext {
|
|
|
2034
1990
|
// Combine the pane and all its child nodes for the history patch
|
|
2035
1991
|
const nodesToHistory = [duplicatedPane as BaseNode, ...allNodes];
|
|
2036
1992
|
|
|
2037
|
-
this.
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
1993
|
+
if (!this.isTemplate.get()) {
|
|
1994
|
+
if (VERBOSE_HISTORY)
|
|
1995
|
+
console.log('[Nodes] Action: addTemplatePane', {
|
|
1996
|
+
id: duplicatedPane.id,
|
|
1997
|
+
slug: duplicatedPane.slug,
|
|
1998
|
+
});
|
|
1999
|
+
this.history.addPatch({
|
|
2000
|
+
op: PatchOp.ADD,
|
|
2001
|
+
undo: (ctx) => {
|
|
2002
|
+
// Delete all nodes created (pane + children)
|
|
2003
|
+
ctx.deleteNodes(nodesToHistory);
|
|
2042
2004
|
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
storyFragmentNode.paneIds.push(duplicatedPane.id);
|
|
2058
|
-
} else {
|
|
2059
|
-
if (location === 'before') {
|
|
2060
|
-
storyFragmentNode.paneIds.splice(elIdx, 0, duplicatedPane.id);
|
|
2005
|
+
if (
|
|
2006
|
+
storyFragmentNode &&
|
|
2007
|
+
storyFragmentNode.nodeType === 'StoryFragment' &&
|
|
2008
|
+
Array.isArray(storyFragmentNode.paneIds)
|
|
2009
|
+
) {
|
|
2010
|
+
storyFragmentNode.paneIds = storyFragmentNode.paneIds.filter(
|
|
2011
|
+
(id: string) => id !== duplicatedPane.id
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
},
|
|
2015
|
+
redo: (ctx) => {
|
|
2016
|
+
if (storyFragmentNode?.nodeType === 'StoryFragment') {
|
|
2017
|
+
if (elIdx === -1) {
|
|
2018
|
+
storyFragmentNode.paneIds.push(duplicatedPane.id);
|
|
2061
2019
|
} else {
|
|
2062
|
-
|
|
2020
|
+
if (location === 'before') {
|
|
2021
|
+
storyFragmentNode.paneIds.splice(elIdx, 0, duplicatedPane.id);
|
|
2022
|
+
} else {
|
|
2023
|
+
storyFragmentNode.paneIds.splice(
|
|
2024
|
+
elIdx + 1,
|
|
2025
|
+
0,
|
|
2026
|
+
duplicatedPane.id
|
|
2027
|
+
);
|
|
2028
|
+
}
|
|
2063
2029
|
}
|
|
2064
2030
|
}
|
|
2065
|
-
storyFragmentNode.isChanged = true;
|
|
2066
|
-
}
|
|
2067
2031
|
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2032
|
+
// Add all nodes back (pane + children)
|
|
2033
|
+
ctx.addNodes(nodesToHistory);
|
|
2034
|
+
ctx.linkChildToParent(
|
|
2035
|
+
duplicatedPane.id,
|
|
2036
|
+
duplicatedPane.parentId,
|
|
2037
|
+
specificIdx
|
|
2038
|
+
);
|
|
2039
|
+
},
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2077
2042
|
|
|
2078
2043
|
return duplicatedPaneId;
|
|
2079
2044
|
}
|
|
@@ -2117,11 +2082,18 @@ export class NodesContext {
|
|
|
2117
2082
|
targetId
|
|
2118
2083
|
);
|
|
2119
2084
|
this.addNodes(flattenedNodes);
|
|
2120
|
-
this.
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2085
|
+
if (!this.isTemplate.get()) {
|
|
2086
|
+
if (VERBOSE_HISTORY)
|
|
2087
|
+
console.log('[Nodes] Action: addTemplateImpressionNode', {
|
|
2088
|
+
targetId,
|
|
2089
|
+
nodeCount: flattenedNodes.length,
|
|
2090
|
+
});
|
|
2091
|
+
this.history.addPatch({
|
|
2092
|
+
op: PatchOp.ADD,
|
|
2093
|
+
undo: (ctx) => ctx.deleteNodes(flattenedNodes),
|
|
2094
|
+
redo: (ctx) => ctx.addNodes(flattenedNodes),
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2125
2097
|
}
|
|
2126
2098
|
|
|
2127
2099
|
addTemplateNode(
|
|
@@ -2234,7 +2206,7 @@ export class NodesContext {
|
|
|
2234
2206
|
|
|
2235
2207
|
// 5. PERFORM REMAINING STATE MUTATIONS
|
|
2236
2208
|
if (originalPaneNode) {
|
|
2237
|
-
this.modifyNodes([{ ...originalPaneNode
|
|
2209
|
+
this.modifyNodes([{ ...originalPaneNode }], {
|
|
2238
2210
|
notify: false,
|
|
2239
2211
|
recordHistory: false,
|
|
2240
2212
|
});
|
|
@@ -2266,54 +2238,61 @@ export class NodesContext {
|
|
|
2266
2238
|
}
|
|
2267
2239
|
|
|
2268
2240
|
// 6. RECORD THE ENTIRE ATOMIC OPERATION in a single history patch.
|
|
2269
|
-
this.
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
currentChildren.
|
|
2241
|
+
if (!this.isTemplate.get()) {
|
|
2242
|
+
if (VERBOSE_HISTORY)
|
|
2243
|
+
console.log('[Nodes] Action: addTemplateNode', {
|
|
2244
|
+
targetId,
|
|
2245
|
+
nodeCount: flattenedNodes.length,
|
|
2246
|
+
});
|
|
2247
|
+
this.history.addPatch({
|
|
2248
|
+
op: PatchOp.ADD,
|
|
2249
|
+
undo: (ctx) => {
|
|
2250
|
+
// Undo all changes: delete the element and the auto-created markdown node (if it exists)
|
|
2251
|
+
ctx.deleteNodes(flattenedNodes);
|
|
2252
|
+
if (autoCreatedMarkdownNode) {
|
|
2253
|
+
ctx.deleteNodes([autoCreatedMarkdownNode]);
|
|
2254
|
+
}
|
|
2255
|
+
if (originalPaneNode) {
|
|
2256
|
+
const newNodes = new Map(ctx.allNodes.get());
|
|
2257
|
+
newNodes.set(originalPaneNode.id, originalPaneNode);
|
|
2258
|
+
ctx.allNodes.set(newNodes);
|
|
2259
|
+
}
|
|
2260
|
+
if (paneNodeId) ctx.notifyNode(paneNodeId);
|
|
2261
|
+
},
|
|
2262
|
+
redo: (ctx) => {
|
|
2263
|
+
// Redo all changes in the correct order
|
|
2264
|
+
if (originalPaneNode) {
|
|
2265
|
+
ctx.modifyNodes([{ ...originalPaneNode }], {
|
|
2266
|
+
notify: false,
|
|
2267
|
+
recordHistory: false,
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
if (autoCreatedMarkdownNode) {
|
|
2271
|
+
ctx.addNode(autoCreatedMarkdownNode);
|
|
2272
|
+
}
|
|
2273
|
+
ctx.addNodes(flattenedNodes);
|
|
2274
|
+
|
|
2275
|
+
// Re-apply insertion logic
|
|
2276
|
+
const parentNodesMap = ctx.parentNodes.get();
|
|
2277
|
+
const parentChildren = parentNodesMap.get(parentId);
|
|
2278
|
+
if (insertNodeId && location && parentChildren) {
|
|
2279
|
+
const insertIndex = parentChildren.indexOf(insertNodeId);
|
|
2280
|
+
if (insertIndex !== -1) {
|
|
2281
|
+
const currentChildren = parentChildren.filter(
|
|
2282
|
+
(id) => !newTopLevelIds.includes(id)
|
|
2283
|
+
);
|
|
2284
|
+
if (location === 'before') {
|
|
2285
|
+
currentChildren.splice(insertIndex, 0, ...newTopLevelIds);
|
|
2286
|
+
} else {
|
|
2287
|
+
currentChildren.splice(insertIndex + 1, 0, ...newTopLevelIds);
|
|
2288
|
+
}
|
|
2289
|
+
parentNodesMap.set(parentId, currentChildren);
|
|
2310
2290
|
}
|
|
2311
|
-
parentNodesMap.set(parentId, currentChildren);
|
|
2312
2291
|
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2292
|
+
if (paneNodeId) ctx.notifyNode(paneNodeId);
|
|
2293
|
+
},
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2317
2296
|
|
|
2318
2297
|
// 7. SEND A SINGLE NOTIFICATION to update the UI.
|
|
2319
2298
|
if (paneNodeId) {
|
|
@@ -2486,7 +2465,7 @@ export class NodesContext {
|
|
|
2486
2465
|
this.allNodes.get().get(paneNodeId)
|
|
2487
2466
|
) as PaneNode;
|
|
2488
2467
|
if (paneNode) {
|
|
2489
|
-
this.modifyNodes([{ ...paneNode
|
|
2468
|
+
this.modifyNodes([{ ...paneNode }]);
|
|
2490
2469
|
}
|
|
2491
2470
|
}
|
|
2492
2471
|
}
|
|
@@ -2498,23 +2477,29 @@ export class NodesContext {
|
|
|
2498
2477
|
|
|
2499
2478
|
this.notifyNode(ROOT_NODE_NAME);
|
|
2500
2479
|
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
this.
|
|
2480
|
+
if (!this.isTemplate.get()) {
|
|
2481
|
+
if (VERBOSE_HISTORY)
|
|
2482
|
+
console.log('[Nodes] Action: deleteNode', {
|
|
2483
|
+
targetNodeId,
|
|
2484
|
+
deletedCount: toDelete.length,
|
|
2485
|
+
});
|
|
2486
|
+
this.history.addPatch({
|
|
2487
|
+
op: PatchOp.REMOVE,
|
|
2488
|
+
undo: (ctx) => {
|
|
2489
|
+
ctx.addNodes(toDelete);
|
|
2490
|
+
if (targetNode.nodeType === 'Pane' && parentId !== null) {
|
|
2491
|
+
const storyFragment = this.allNodes
|
|
2492
|
+
.get()
|
|
2493
|
+
.get(parentId) as StoryFragmentNode;
|
|
2494
|
+
if (storyFragment) {
|
|
2495
|
+
storyFragment.paneIds.splice(paneIdx, 0, targetNodeId);
|
|
2496
|
+
this.linkChildToParent(targetNodeId, parentId, paneIdx);
|
|
2497
|
+
}
|
|
2513
2498
|
}
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
}
|
|
2499
|
+
},
|
|
2500
|
+
redo: (ctx) => ctx.deleteNodes(toDelete),
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2518
2503
|
}
|
|
2519
2504
|
|
|
2520
2505
|
getNodesRecursively(node: BaseNode | undefined): BaseNode[] {
|
|
@@ -2611,7 +2596,7 @@ export class NodesContext {
|
|
|
2611
2596
|
this.allNodes.get().get(storyFragmentId)
|
|
2612
2597
|
) as StoryFragmentNode;
|
|
2613
2598
|
if (storyFragment) {
|
|
2614
|
-
this.modifyNodes([{ ...storyFragment
|
|
2599
|
+
this.modifyNodes([{ ...storyFragment }]);
|
|
2615
2600
|
}
|
|
2616
2601
|
} else {
|
|
2617
2602
|
const parentNode = this.nodeToNotify(
|
|
@@ -2621,64 +2606,72 @@ export class NodesContext {
|
|
|
2621
2606
|
this.notifyNode(parentNode || '');
|
|
2622
2607
|
}
|
|
2623
2608
|
|
|
2624
|
-
this.
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
);
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
node.parentId = oldParentId;
|
|
2638
|
-
|
|
2639
|
-
if (node.nodeType === 'Pane' && originalPaneIds) {
|
|
2640
|
-
const storyFragmentId = ctx.getClosestNodeTypeFromId(
|
|
2641
|
-
node.id,
|
|
2642
|
-
'StoryFragment'
|
|
2609
|
+
if (!this.isTemplate.get()) {
|
|
2610
|
+
if (VERBOSE_HISTORY)
|
|
2611
|
+
console.log('[Nodes] Action: moveNodeTo', {
|
|
2612
|
+
nodeId,
|
|
2613
|
+
insertNodeId,
|
|
2614
|
+
location,
|
|
2615
|
+
});
|
|
2616
|
+
this.history.addPatch({
|
|
2617
|
+
op: PatchOp.REPLACE,
|
|
2618
|
+
undo: (ctx) => {
|
|
2619
|
+
const oldParentNodes = ctx.getChildNodeIDs(node.parentId || '');
|
|
2620
|
+
const newParentNodes = ctx.getChildNodeIDs(
|
|
2621
|
+
newLocationNode.parentId || ''
|
|
2643
2622
|
);
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
) as StoryFragmentNode;
|
|
2647
|
-
if (storyFragment) {
|
|
2648
|
-
storyFragment.paneIds = [...originalPaneIds];
|
|
2649
|
-
this.modifyNodes([{ ...storyFragment, isChanged: true }]);
|
|
2623
|
+
if (newParentNodes) {
|
|
2624
|
+
newParentNodes.splice(newParentNodes.indexOf(nodeId), 1);
|
|
2650
2625
|
}
|
|
2651
|
-
|
|
2626
|
+
if (oldParentNodes) {
|
|
2627
|
+
oldParentNodes.splice(originalIdx, 0, nodeId);
|
|
2628
|
+
}
|
|
2629
|
+
node.parentId = oldParentId;
|
|
2652
2630
|
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
);
|
|
2631
|
+
if (node.nodeType === 'Pane' && originalPaneIds) {
|
|
2632
|
+
const storyFragmentId = ctx.getClosestNodeTypeFromId(
|
|
2633
|
+
node.id,
|
|
2634
|
+
'StoryFragment'
|
|
2635
|
+
);
|
|
2636
|
+
const storyFragment = cloneDeep(
|
|
2637
|
+
ctx.allNodes.get().get(storyFragmentId)
|
|
2638
|
+
) as StoryFragmentNode;
|
|
2639
|
+
if (storyFragment) {
|
|
2640
|
+
storyFragment.paneIds = [...originalPaneIds];
|
|
2641
|
+
this.modifyNodes([{ ...storyFragment }]);
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2667
2644
|
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2645
|
+
//const parentNode = ctx.nodeToNotify(node?.parentId || "", node.nodeType);
|
|
2646
|
+
ctx.notifyNode(node.id || '');
|
|
2647
|
+
},
|
|
2648
|
+
redo: (ctx) => {
|
|
2649
|
+
moveNodeAtLocationInContext(
|
|
2650
|
+
oldParentNodes,
|
|
2651
|
+
originalIdx,
|
|
2652
|
+
newLocationNode,
|
|
2653
|
+
insertNodeId,
|
|
2654
|
+
nodeId,
|
|
2655
|
+
location,
|
|
2656
|
+
node,
|
|
2657
|
+
ctx
|
|
2672
2658
|
);
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2659
|
+
|
|
2660
|
+
if (node.nodeType === 'Pane') {
|
|
2661
|
+
const storyFragmentId = ctx.getClosestNodeTypeFromId(
|
|
2662
|
+
node.id,
|
|
2663
|
+
'StoryFragment'
|
|
2664
|
+
);
|
|
2665
|
+
const storyFragment = cloneDeep(
|
|
2666
|
+
ctx.allNodes.get().get(storyFragmentId)
|
|
2667
|
+
) as StoryFragmentNode;
|
|
2668
|
+
if (storyFragment) {
|
|
2669
|
+
this.modifyNodes([{ ...storyFragment }]);
|
|
2670
|
+
}
|
|
2678
2671
|
}
|
|
2679
|
-
}
|
|
2680
|
-
}
|
|
2681
|
-
}
|
|
2672
|
+
},
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2682
2675
|
}
|
|
2683
2676
|
|
|
2684
2677
|
getPaneImageFileIds(paneId: string): string[] {
|
|
@@ -2772,7 +2765,6 @@ export class NodesContext {
|
|
|
2772
2765
|
const updatedStoryFragment: StoryFragmentNode = {
|
|
2773
2766
|
...storyfragment,
|
|
2774
2767
|
paneIds: newPaneIds,
|
|
2775
|
-
isChanged: true,
|
|
2776
2768
|
};
|
|
2777
2769
|
|
|
2778
2770
|
// Pass the correctly typed object to modifyNodes
|
|
@@ -3202,7 +3194,7 @@ export class NodesContext {
|
|
|
3202
3194
|
this.parentNodes.set(newParentNodes);
|
|
3203
3195
|
|
|
3204
3196
|
// Mark pane as dirty
|
|
3205
|
-
this.modifyNodes([{ ...originalPaneNode
|
|
3197
|
+
this.modifyNodes([{ ...originalPaneNode }], {
|
|
3206
3198
|
notify: false,
|
|
3207
3199
|
recordHistory: false,
|
|
3208
3200
|
});
|
|
@@ -3228,41 +3220,15 @@ export class NodesContext {
|
|
|
3228
3220
|
// --- 5. Execute the operation and add to history ---
|
|
3229
3221
|
applyUnwrap();
|
|
3230
3222
|
|
|
3231
|
-
this.
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
* results to the main context in a single operation, triggering one UI update.
|
|
3241
|
-
* @param work - An async function that receives the temporary context and performs modifications.
|
|
3242
|
-
*/
|
|
3243
|
-
async applyAtomicUpdate(
|
|
3244
|
-
work: (tmpCtx: NodesContext) => Promise<void>
|
|
3245
|
-
): Promise<void> {
|
|
3246
|
-
// 1. Create a temporary, "off-screen" context
|
|
3247
|
-
const tmpCtx = new NodesContext();
|
|
3248
|
-
// Prime the temp context with the same root ID and other relevant state
|
|
3249
|
-
tmpCtx.rootNodeId.set(this.rootNodeId.get());
|
|
3250
|
-
tmpCtx.allNodes.set(new Map(this.allNodes.get()));
|
|
3251
|
-
tmpCtx.parentNodes.set(new Map(this.parentNodes.get()));
|
|
3252
|
-
|
|
3253
|
-
// 2. Execute the long-running work on the temporary context
|
|
3254
|
-
await work(tmpCtx);
|
|
3255
|
-
|
|
3256
|
-
// 3. Get the results from the temporary context
|
|
3257
|
-
const newNodes = tmpCtx.allNodes.get();
|
|
3258
|
-
const newParentRelations = tmpCtx.parentNodes.get();
|
|
3259
|
-
|
|
3260
|
-
// 4. Swap/Merge the results into the main context
|
|
3261
|
-
this.allNodes.set(newNodes);
|
|
3262
|
-
this.parentNodes.set(newParentRelations);
|
|
3263
|
-
|
|
3264
|
-
// 5. Trigger a single notification to re-render the UI
|
|
3265
|
-
this.notifyNode('root');
|
|
3223
|
+
if (!this.isTemplate.get()) {
|
|
3224
|
+
if (VERBOSE_HISTORY)
|
|
3225
|
+
console.log('[Nodes] Action: unwrapNode', { nodeId });
|
|
3226
|
+
this.history.addPatch({
|
|
3227
|
+
op: PatchOp.REPLACE, // Using REPLACE as it's a complex operation
|
|
3228
|
+
undo: () => applyRewrap(),
|
|
3229
|
+
redo: () => applyUnwrap(),
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3266
3232
|
}
|
|
3267
3233
|
|
|
3268
3234
|
private deleteNodes(nodesList: BaseNode[]): BaseNode[] {
|