@case-framework/survey-core 0.3.0 → 0.4.1
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/README.md +31 -34
- package/build/editor.d.mts +78 -19
- package/build/editor.d.mts.map +1 -1
- package/build/editor.mjs +247 -43
- package/build/editor.mjs.map +1 -1
- package/build/index.d.mts +76 -54
- package/build/index.d.mts.map +1 -1
- package/build/index.mjs +171 -69
- package/build/index.mjs.map +1 -1
- package/build/package.json +27 -27
- package/build/{survey-wnGyIY66.d.mts → survey-BV8YHc3J.d.mts} +378 -86
- package/build/survey-BV8YHc3J.d.mts.map +1 -0
- package/build/{survey-DJbgFVPz.mjs → survey-DnLtf19j.mjs} +429 -32
- package/build/survey-DnLtf19j.mjs.map +1 -0
- package/package.json +21 -21
- package/build/survey-DJbgFVPz.mjs.map +0 -1
- package/build/survey-wnGyIY66.d.mts.map +0 -1
package/build/editor.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as generateId, a as getContentPlainText, nt as structuredCloneMethod, t as Survey, u as SurveyItemTranslations, v as GroupItemCore } from "./survey-DnLtf19j.mjs";
|
|
2
2
|
//#region src/editor/ai-context.ts
|
|
3
3
|
const DEFAULT_SCOPE_LIMITS = {
|
|
4
4
|
tiny: 40,
|
|
@@ -174,10 +174,7 @@ const normalizeSnippetText = (text, maxChars) => {
|
|
|
174
174
|
return text.trim().replace(/\s+/g, " ").slice(0, maxChars);
|
|
175
175
|
};
|
|
176
176
|
const getContentText = (content, maxChars) => {
|
|
177
|
-
|
|
178
|
-
const maybeText = content.content;
|
|
179
|
-
if (typeof maybeText !== "string") return null;
|
|
180
|
-
const normalized = normalizeSnippetText(maybeText, maxChars);
|
|
177
|
+
const normalized = normalizeSnippetText(getContentPlainText(content), maxChars);
|
|
181
178
|
return normalized.length > 0 ? normalized : null;
|
|
182
179
|
};
|
|
183
180
|
function getItemTranslationSnippets(survey, itemId, maxSnippets, textLimit) {
|
|
@@ -439,7 +436,7 @@ var ItemCopyPaste = class ItemCopyPaste {
|
|
|
439
436
|
*/
|
|
440
437
|
updateItemIdsInData(itemData, idMapping) {
|
|
441
438
|
const updatedData = JSON.parse(JSON.stringify(itemData));
|
|
442
|
-
if (updatedData.itemType ===
|
|
439
|
+
if (updatedData.itemType === "group" && updatedData.config) {
|
|
443
440
|
const config = updatedData.config;
|
|
444
441
|
if (config.items) config.items = config.items.map((childId) => idMapping[childId] ?? childId);
|
|
445
442
|
}
|
|
@@ -460,6 +457,11 @@ var ItemCopyPaste = class ItemCopyPaste {
|
|
|
460
457
|
if (itemData.validations) Object.values(itemData.validations).forEach((expr) => {
|
|
461
458
|
if (expr) this.updateExpressionReferences(expr, idMapping);
|
|
462
459
|
});
|
|
460
|
+
if (itemData.prefills) itemData.prefills.forEach((prefill) => {
|
|
461
|
+
if (prefill.when) this.updateExpressionReferences(prefill.when, idMapping);
|
|
462
|
+
if (prefill.source.type === "expression") this.updateExpressionReferences(prefill.source.expression, idMapping);
|
|
463
|
+
if (prefill.source.type === "previousResponse") prefill.source.ref.itemId = idMapping[prefill.source.ref.itemId] ?? prefill.source.ref.itemId;
|
|
464
|
+
});
|
|
463
465
|
}
|
|
464
466
|
/**
|
|
465
467
|
* Update references in a single expression (recursive)
|
|
@@ -528,52 +530,152 @@ var MemoryCalculator = class {
|
|
|
528
530
|
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
|
529
531
|
}
|
|
530
532
|
};
|
|
533
|
+
function cloneAssets(assets) {
|
|
534
|
+
if (!assets || Object.keys(assets).length === 0) return;
|
|
535
|
+
return structuredCloneMethod(assets);
|
|
536
|
+
}
|
|
537
|
+
function normalizeHistoryEntry(entry) {
|
|
538
|
+
if ("kind" in entry) {
|
|
539
|
+
if (entry.kind === "survey-snapshot") return {
|
|
540
|
+
kind: "survey-snapshot",
|
|
541
|
+
survey: structuredCloneMethod(entry.survey),
|
|
542
|
+
timestamp: entry.timestamp,
|
|
543
|
+
meta: entry.meta,
|
|
544
|
+
memorySize: entry.memorySize
|
|
545
|
+
};
|
|
546
|
+
return {
|
|
547
|
+
kind: "asset-change",
|
|
548
|
+
changes: structuredCloneMethod(entry.changes),
|
|
549
|
+
timestamp: entry.timestamp,
|
|
550
|
+
meta: entry.meta,
|
|
551
|
+
memorySize: entry.memorySize
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
return {
|
|
555
|
+
kind: "survey-snapshot",
|
|
556
|
+
survey: structuredCloneMethod(entry.survey),
|
|
557
|
+
timestamp: entry.timestamp,
|
|
558
|
+
meta: entry.meta,
|
|
559
|
+
memorySize: entry.memorySize
|
|
560
|
+
};
|
|
561
|
+
}
|
|
531
562
|
var SurveyEditorUndoRedo = class SurveyEditorUndoRedo {
|
|
532
563
|
history = [];
|
|
533
564
|
currentIndex = -1;
|
|
534
565
|
_config;
|
|
566
|
+
_initialAssets;
|
|
535
567
|
constructor(initialSurvey, config = {}, meta = {
|
|
536
568
|
label: "Initial state",
|
|
537
569
|
source: CommitSource.SYSTEM
|
|
538
|
-
}) {
|
|
570
|
+
}, initialAssets) {
|
|
539
571
|
this._config = {
|
|
540
572
|
maxTotalMemoryMB: 50,
|
|
541
573
|
minHistorySize: 10,
|
|
542
574
|
maxHistorySize: 200,
|
|
543
575
|
...config
|
|
544
576
|
};
|
|
577
|
+
this._initialAssets = cloneAssets(initialAssets);
|
|
545
578
|
this.saveSnapshot(initialSurvey, meta);
|
|
546
579
|
}
|
|
547
|
-
|
|
548
|
-
const
|
|
580
|
+
saveEntry(entry) {
|
|
581
|
+
const payload = entry.kind === "survey-snapshot" ? {
|
|
582
|
+
kind: entry.kind,
|
|
583
|
+
survey: entry.survey
|
|
584
|
+
} : {
|
|
585
|
+
kind: entry.kind,
|
|
586
|
+
changes: entry.changes
|
|
587
|
+
};
|
|
588
|
+
const memorySize = MemoryCalculator.calculateSize(payload);
|
|
549
589
|
this.history = this.history.slice(0, this.currentIndex + 1);
|
|
550
590
|
this.history.push({
|
|
551
|
-
|
|
591
|
+
...structuredCloneMethod(entry),
|
|
552
592
|
timestamp: Date.now(),
|
|
553
|
-
meta,
|
|
554
593
|
memorySize
|
|
555
594
|
});
|
|
556
595
|
this.currentIndex++;
|
|
557
596
|
this.cleanupHistory();
|
|
558
597
|
}
|
|
598
|
+
saveSnapshot(survey, meta) {
|
|
599
|
+
this.saveEntry({
|
|
600
|
+
kind: "survey-snapshot",
|
|
601
|
+
survey: structuredCloneMethod(survey),
|
|
602
|
+
meta
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
getBaseAssetsSize() {
|
|
606
|
+
return this._initialAssets ? MemoryCalculator.calculateSize(this._initialAssets) : 0;
|
|
607
|
+
}
|
|
559
608
|
cleanupHistory() {
|
|
560
|
-
let totalMemory = this.getTotalMemoryUsage();
|
|
561
609
|
const maxMemoryBytes = this._config.maxTotalMemoryMB * 1024 * 1024;
|
|
562
|
-
while (this.history.length > this._config.minHistorySize && (
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
610
|
+
while (this.history.length > this._config.minHistorySize && (this.getTotalMemoryUsage() > maxMemoryBytes || this.history.length > this._config.maxHistorySize)) if (this.dropOldestState() <= 0) break;
|
|
611
|
+
}
|
|
612
|
+
dropOldestState() {
|
|
613
|
+
if (this.history.length <= 1) return 0;
|
|
614
|
+
const nextStateIndex = 1;
|
|
615
|
+
const nextStateSurvey = this.getStateAtIndex(nextStateIndex);
|
|
616
|
+
const nextStateAssets = this.getAssetsAtIndex(nextStateIndex);
|
|
617
|
+
const nextEntry = this.history[nextStateIndex];
|
|
618
|
+
const newFirstEntry = {
|
|
619
|
+
kind: "survey-snapshot",
|
|
620
|
+
survey: nextStateSurvey,
|
|
621
|
+
meta: nextEntry.meta,
|
|
622
|
+
timestamp: nextEntry.timestamp,
|
|
623
|
+
memorySize: MemoryCalculator.calculateSize({
|
|
624
|
+
kind: "survey-snapshot",
|
|
625
|
+
survey: nextStateSurvey
|
|
626
|
+
})
|
|
627
|
+
};
|
|
628
|
+
const removedBytes = this.history[0].memorySize;
|
|
629
|
+
this._initialAssets = cloneAssets(nextStateAssets);
|
|
630
|
+
this.history = [newFirstEntry, ...this.history.slice(nextStateIndex + 1)];
|
|
631
|
+
this.currentIndex--;
|
|
632
|
+
return removedBytes;
|
|
567
633
|
}
|
|
568
634
|
getTotalMemoryUsage() {
|
|
569
|
-
return this.history.reduce((total, entry) => total + entry.memorySize, 0);
|
|
635
|
+
return this.getBaseAssetsSize() + this.history.reduce((total, entry) => total + entry.memorySize, 0);
|
|
636
|
+
}
|
|
637
|
+
getStateAtIndex(index) {
|
|
638
|
+
if (index < 0 || index >= this.history.length) throw new Error("Invalid history state");
|
|
639
|
+
for (let i = index; i >= 0; i--) {
|
|
640
|
+
const entry = this.history[i];
|
|
641
|
+
if (entry.kind === "survey-snapshot") return structuredCloneMethod(entry.survey);
|
|
642
|
+
}
|
|
643
|
+
throw new Error("Invalid history state");
|
|
644
|
+
}
|
|
645
|
+
applyAssetPatch(assets, patch) {
|
|
646
|
+
const nextAssets = structuredCloneMethod(assets);
|
|
647
|
+
if (patch.next) nextAssets[patch.assetId] = structuredCloneMethod(patch.next);
|
|
648
|
+
else delete nextAssets[patch.assetId];
|
|
649
|
+
return nextAssets;
|
|
650
|
+
}
|
|
651
|
+
getAssetsAtIndex(index) {
|
|
652
|
+
if (index < 0 || index >= this.history.length) throw new Error("Invalid history state");
|
|
653
|
+
let assets = cloneAssets(this._initialAssets) ?? {};
|
|
654
|
+
for (let i = 1; i <= index; i++) {
|
|
655
|
+
const entry = this.history[i];
|
|
656
|
+
if (entry.kind !== "asset-change") continue;
|
|
657
|
+
for (const patch of entry.changes) assets = this.applyAssetPatch(assets, patch);
|
|
658
|
+
}
|
|
659
|
+
return Object.keys(assets).length > 0 ? assets : void 0;
|
|
570
660
|
}
|
|
571
661
|
commit(survey, meta) {
|
|
572
662
|
this.saveSnapshot(survey, meta);
|
|
573
663
|
}
|
|
664
|
+
commitAssetChange(changes, meta) {
|
|
665
|
+
if (changes.length === 0) return;
|
|
666
|
+
this.saveEntry({
|
|
667
|
+
kind: "asset-change",
|
|
668
|
+
changes: structuredCloneMethod(changes),
|
|
669
|
+
meta
|
|
670
|
+
});
|
|
671
|
+
}
|
|
574
672
|
getCurrentState() {
|
|
575
673
|
if (this.currentIndex < 0 || this.currentIndex >= this.history.length) throw new Error("Invalid history state");
|
|
576
|
-
return
|
|
674
|
+
return this.getStateAtIndex(this.currentIndex);
|
|
675
|
+
}
|
|
676
|
+
getCurrentAssets() {
|
|
677
|
+
if (this.currentIndex < 0 || this.currentIndex >= this.history.length) throw new Error("Invalid history state");
|
|
678
|
+
return this.getAssetsAtIndex(this.currentIndex);
|
|
577
679
|
}
|
|
578
680
|
undo() {
|
|
579
681
|
if (!this.canUndo()) return null;
|
|
@@ -614,6 +716,7 @@ var SurveyEditorUndoRedo = class SurveyEditorUndoRedo {
|
|
|
614
716
|
getHistory() {
|
|
615
717
|
return this.history.map((entry, index) => ({
|
|
616
718
|
index,
|
|
719
|
+
kind: entry.kind,
|
|
617
720
|
meta: entry.meta,
|
|
618
721
|
timestamp: entry.timestamp,
|
|
619
722
|
memorySize: entry.memorySize,
|
|
@@ -621,6 +724,25 @@ var SurveyEditorUndoRedo = class SurveyEditorUndoRedo {
|
|
|
621
724
|
}));
|
|
622
725
|
}
|
|
623
726
|
/**
|
|
727
|
+
* Get committed history entries after the initial state up to the current index.
|
|
728
|
+
*
|
|
729
|
+
* Redo-only future entries are intentionally omitted so the returned list describes the active
|
|
730
|
+
* change chain from the initial state to the current editor state.
|
|
731
|
+
*/
|
|
732
|
+
getCommitsSinceInitial() {
|
|
733
|
+
return this.history.slice(1, this.currentIndex + 1).map((entry, offset) => {
|
|
734
|
+
const index = offset + 1;
|
|
735
|
+
return {
|
|
736
|
+
index,
|
|
737
|
+
kind: entry.kind,
|
|
738
|
+
meta: entry.meta,
|
|
739
|
+
timestamp: entry.timestamp,
|
|
740
|
+
memorySize: entry.memorySize,
|
|
741
|
+
isCurrent: index === this.currentIndex
|
|
742
|
+
};
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
624
746
|
* Get the current index in the history
|
|
625
747
|
*/
|
|
626
748
|
getCurrentIndex() {
|
|
@@ -654,14 +776,25 @@ var SurveyEditorUndoRedo = class SurveyEditorUndoRedo {
|
|
|
654
776
|
*/
|
|
655
777
|
serialize() {
|
|
656
778
|
return {
|
|
657
|
-
history: this.history.map((entry) =>
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
779
|
+
history: this.history.map((entry) => {
|
|
780
|
+
if (entry.kind === "survey-snapshot") return {
|
|
781
|
+
kind: "survey-snapshot",
|
|
782
|
+
survey: entry.survey,
|
|
783
|
+
timestamp: entry.timestamp,
|
|
784
|
+
meta: entry.meta,
|
|
785
|
+
memorySize: entry.memorySize
|
|
786
|
+
};
|
|
787
|
+
return {
|
|
788
|
+
kind: "asset-change",
|
|
789
|
+
changes: entry.changes,
|
|
790
|
+
timestamp: entry.timestamp,
|
|
791
|
+
meta: entry.meta,
|
|
792
|
+
memorySize: entry.memorySize
|
|
793
|
+
};
|
|
794
|
+
}),
|
|
663
795
|
currentIndex: this.currentIndex,
|
|
664
|
-
config: { ...this._config }
|
|
796
|
+
config: { ...this._config },
|
|
797
|
+
initialAssets: cloneAssets(this._initialAssets)
|
|
665
798
|
};
|
|
666
799
|
}
|
|
667
800
|
/**
|
|
@@ -669,23 +802,34 @@ var SurveyEditorUndoRedo = class SurveyEditorUndoRedo {
|
|
|
669
802
|
* @param jsonData The serialized undo/redo state
|
|
670
803
|
* @returns A new SurveyEditorUndoRedo instance with the restored state
|
|
671
804
|
*/
|
|
672
|
-
static deserialize(jsonData) {
|
|
805
|
+
static deserialize(jsonData, initialAssetsOverride) {
|
|
673
806
|
if (!jsonData.history || !Array.isArray(jsonData.history) || jsonData.history.length === 0) throw new Error("Invalid object: history must be an array and must not be empty");
|
|
674
807
|
if (typeof jsonData.currentIndex !== "number" || jsonData.currentIndex < 0 || jsonData.currentIndex >= jsonData.history.length) throw new Error("Invalid object: currentIndex must be a valid index within the history array");
|
|
675
808
|
if (!jsonData.config) throw new Error("Invalid object: config is required");
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}));
|
|
809
|
+
const normalizedHistory = jsonData.history.map(normalizeHistoryEntry);
|
|
810
|
+
const firstEntry = normalizedHistory[0];
|
|
811
|
+
const instance = new SurveyEditorUndoRedo(firstEntry.kind === "survey-snapshot" ? firstEntry.survey : (() => {
|
|
812
|
+
throw new Error("Invalid object: first history entry must resolve to a survey snapshot");
|
|
813
|
+
})(), jsonData.config, firstEntry.meta, initialAssetsOverride ?? jsonData.initialAssets);
|
|
814
|
+
instance.history = normalizedHistory;
|
|
683
815
|
instance.currentIndex = jsonData.currentIndex;
|
|
816
|
+
instance._initialAssets = cloneAssets(initialAssetsOverride ?? jsonData.initialAssets);
|
|
684
817
|
return instance;
|
|
685
818
|
}
|
|
686
819
|
};
|
|
687
820
|
//#endregion
|
|
688
821
|
//#region src/editor/survey-editor.ts
|
|
822
|
+
function stripAssetsFromSurveySnapshot(survey) {
|
|
823
|
+
const snapshot = structuredCloneMethod(survey);
|
|
824
|
+
delete snapshot.assets;
|
|
825
|
+
return snapshot;
|
|
826
|
+
}
|
|
827
|
+
function mergeSurveySnapshotWithAssets(snapshot, assets) {
|
|
828
|
+
const merged = structuredCloneMethod(snapshot);
|
|
829
|
+
if (assets && Object.keys(assets).length > 0) merged.assets = structuredCloneMethod(assets);
|
|
830
|
+
else delete merged.assets;
|
|
831
|
+
return merged;
|
|
832
|
+
}
|
|
689
833
|
var SurveyEditor = class SurveyEditor {
|
|
690
834
|
_survey;
|
|
691
835
|
_undoRedo;
|
|
@@ -695,7 +839,8 @@ var SurveyEditor = class SurveyEditor {
|
|
|
695
839
|
this._survey = survey;
|
|
696
840
|
const { pluginRegistry, ...undoRedoConfig } = config;
|
|
697
841
|
this._pluginRegistry = pluginRegistry;
|
|
698
|
-
|
|
842
|
+
const serialized = survey.serialize();
|
|
843
|
+
this._undoRedo = new SurveyEditorUndoRedo(stripAssetsFromSurveySnapshot(serialized), undoRedoConfig, meta, serialized.assets);
|
|
699
844
|
}
|
|
700
845
|
/** Returns an immutable copy of the current survey state. */
|
|
701
846
|
get survey() {
|
|
@@ -710,9 +855,13 @@ var SurveyEditor = class SurveyEditor {
|
|
|
710
855
|
return this._undoRedo;
|
|
711
856
|
}
|
|
712
857
|
commit(meta) {
|
|
713
|
-
|
|
858
|
+
if (!this._hasUncommittedChanges) return;
|
|
859
|
+
this._undoRedo.commit(stripAssetsFromSurveySnapshot(this._survey.serialize()), meta);
|
|
714
860
|
this._hasUncommittedChanges = false;
|
|
715
861
|
}
|
|
862
|
+
restoreHistoryState(snapshot, assets) {
|
|
863
|
+
this._survey = Survey.fromJson(mergeSurveySnapshotWithAssets(snapshot, assets), this._pluginRegistry);
|
|
864
|
+
}
|
|
716
865
|
commitIfNeeded() {
|
|
717
866
|
if (this._hasUncommittedChanges) this.commit({
|
|
718
867
|
label: "Latest content changes",
|
|
@@ -721,13 +870,13 @@ var SurveyEditor = class SurveyEditor {
|
|
|
721
870
|
}
|
|
722
871
|
undo() {
|
|
723
872
|
if (this._hasUncommittedChanges) {
|
|
724
|
-
this.
|
|
873
|
+
this.restoreHistoryState(this._undoRedo.getCurrentState(), this._undoRedo.getCurrentAssets());
|
|
725
874
|
this._hasUncommittedChanges = false;
|
|
726
875
|
return true;
|
|
727
876
|
} else {
|
|
728
877
|
const previousState = this._undoRedo.undo();
|
|
729
878
|
if (previousState) {
|
|
730
|
-
this.
|
|
879
|
+
this.restoreHistoryState(previousState, this._undoRedo.getCurrentAssets());
|
|
731
880
|
this._hasUncommittedChanges = false;
|
|
732
881
|
return true;
|
|
733
882
|
}
|
|
@@ -738,7 +887,7 @@ var SurveyEditor = class SurveyEditor {
|
|
|
738
887
|
if (this._hasUncommittedChanges) return false;
|
|
739
888
|
const nextState = this._undoRedo.redo();
|
|
740
889
|
if (nextState) {
|
|
741
|
-
this.
|
|
890
|
+
this.restoreHistoryState(nextState, this._undoRedo.getCurrentAssets());
|
|
742
891
|
this._hasUncommittedChanges = false;
|
|
743
892
|
return true;
|
|
744
893
|
}
|
|
@@ -751,7 +900,7 @@ var SurveyEditor = class SurveyEditor {
|
|
|
751
900
|
if (this._hasUncommittedChanges) return false;
|
|
752
901
|
const targetState = this._undoRedo.jumpToIndex(targetIndex);
|
|
753
902
|
if (targetState) {
|
|
754
|
-
this.
|
|
903
|
+
this.restoreHistoryState(targetState, this._undoRedo.getCurrentAssets());
|
|
755
904
|
this._hasUncommittedChanges = false;
|
|
756
905
|
return true;
|
|
757
906
|
}
|
|
@@ -781,6 +930,12 @@ var SurveyEditor = class SurveyEditor {
|
|
|
781
930
|
return this._undoRedo.getConfig();
|
|
782
931
|
}
|
|
783
932
|
/**
|
|
933
|
+
* Get committed changes after the initial editor state up to the current undo/redo position.
|
|
934
|
+
*/
|
|
935
|
+
getCommitsSinceInitial() {
|
|
936
|
+
return this._undoRedo.getCommitsSinceInitial();
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
784
939
|
* Serialize the SurveyEditor state to JSON
|
|
785
940
|
* @returns A JSON-serializable object containing the complete editor state
|
|
786
941
|
*/
|
|
@@ -804,8 +959,14 @@ var SurveyEditor = class SurveyEditor {
|
|
|
804
959
|
if (typeof jsonData.hasUncommittedChanges !== "boolean") throw new Error("Invalid object: hasUncommittedChanges must be a boolean");
|
|
805
960
|
if (jsonData.version && !jsonData.version.startsWith("1.")) console.warn(`Warning: Loading SurveyEditor with version ${jsonData.version}, current version is 1.0.0`);
|
|
806
961
|
const editor = new SurveyEditor(Survey.fromJson(jsonData.survey, pluginRegistry), { pluginRegistry });
|
|
807
|
-
editor._undoRedo = SurveyEditorUndoRedo.deserialize(
|
|
808
|
-
|
|
962
|
+
editor._undoRedo = SurveyEditorUndoRedo.deserialize({
|
|
963
|
+
...jsonData.undoRedo,
|
|
964
|
+
history: jsonData.undoRedo.history.map((entry) => "survey" in entry ? {
|
|
965
|
+
...entry,
|
|
966
|
+
survey: stripAssetsFromSurveySnapshot(entry.survey)
|
|
967
|
+
} : entry)
|
|
968
|
+
}, jsonData.survey.assets);
|
|
969
|
+
editor._hasUncommittedChanges = JSON.stringify(stripAssetsFromSurveySnapshot(jsonData.survey)) !== JSON.stringify(editor._undoRedo.getCurrentState());
|
|
809
970
|
return editor;
|
|
810
971
|
}
|
|
811
972
|
markAsModified() {
|
|
@@ -919,8 +1080,8 @@ var SurveyEditor = class SurveyEditor {
|
|
|
919
1080
|
this.markAsModified();
|
|
920
1081
|
}
|
|
921
1082
|
updateItemTranslations(itemId, updatedContent) {
|
|
1083
|
+
if (!this._survey.surveyItems.get(itemId)) return false;
|
|
922
1084
|
this.markAsModified();
|
|
923
|
-
if (!this._survey.surveyItems.get(itemId)) throw new Error(`Item with id '${itemId}' not found`);
|
|
924
1085
|
this._survey.translations.setItemTranslations(itemId, updatedContent);
|
|
925
1086
|
return true;
|
|
926
1087
|
}
|
|
@@ -996,6 +1157,49 @@ var SurveyEditor = class SurveyEditor {
|
|
|
996
1157
|
this._survey.deleteTemplateValue(key);
|
|
997
1158
|
}
|
|
998
1159
|
/**
|
|
1160
|
+
* Get a survey asset immutably.
|
|
1161
|
+
*/
|
|
1162
|
+
getAsset(assetId) {
|
|
1163
|
+
const asset = this._survey.getAsset(assetId);
|
|
1164
|
+
return asset ? structuredCloneMethod(asset) : void 0;
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Get all survey assets immutably.
|
|
1168
|
+
*/
|
|
1169
|
+
getAssets() {
|
|
1170
|
+
return this._survey.getAssets();
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Add or replace a survey asset.
|
|
1174
|
+
*/
|
|
1175
|
+
setAsset(assetId, asset) {
|
|
1176
|
+
const previousAsset = this._survey.getAsset(assetId);
|
|
1177
|
+
this._survey.setAsset(assetId, structuredCloneMethod(asset));
|
|
1178
|
+
this._undoRedo.commitAssetChange([{
|
|
1179
|
+
assetId,
|
|
1180
|
+
prev: previousAsset,
|
|
1181
|
+
next: structuredCloneMethod(asset)
|
|
1182
|
+
}], {
|
|
1183
|
+
label: `Update asset: ${assetId}`,
|
|
1184
|
+
source: CommitSource.USER
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Remove a survey asset.
|
|
1189
|
+
*/
|
|
1190
|
+
removeAsset(assetId) {
|
|
1191
|
+
const previousAsset = this._survey.getAsset(assetId);
|
|
1192
|
+
if (!previousAsset) return;
|
|
1193
|
+
this._survey.deleteAsset(assetId);
|
|
1194
|
+
this._undoRedo.commitAssetChange([{
|
|
1195
|
+
assetId,
|
|
1196
|
+
prev: previousAsset
|
|
1197
|
+
}], {
|
|
1198
|
+
label: `Remove asset: ${assetId}`,
|
|
1199
|
+
source: CommitSource.USER
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
999
1203
|
* Copy a survey item and all its data to clipboard format
|
|
1000
1204
|
* @param itemId - The ID of the item to copy
|
|
1001
1205
|
* @returns Clipboard data that can be serialized to JSON for clipboard
|