@orion-studios/payload-studio 0.6.0-beta.53 → 0.6.0-beta.55
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/builder-v2/client.js +211 -4
- package/dist/builder-v2/client.mjs +211 -4
- package/dist/index.mjs +3 -3
- package/package.json +1 -1
|
@@ -604,6 +604,7 @@ var decodeHtmlAttribute2 = (value) => {
|
|
|
604
604
|
return decoded;
|
|
605
605
|
};
|
|
606
606
|
var attrToPropName = (name) => name.replace(/^data-orion-/, "").replace(/^data-/, "").replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
607
|
+
var propToAttrName = (name) => `data-orion-${name.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)}`;
|
|
607
608
|
var propsFromAttributes = (attributes = {}) => {
|
|
608
609
|
const props = {};
|
|
609
610
|
Object.keys(attributes).forEach((name) => {
|
|
@@ -646,6 +647,131 @@ var lockPreviewChildren = (component) => {
|
|
|
646
647
|
lockPreviewChildren(child);
|
|
647
648
|
});
|
|
648
649
|
};
|
|
650
|
+
var parseJsonArray = (value) => {
|
|
651
|
+
const decoded = decodeHtmlAttribute2(value);
|
|
652
|
+
if (!decoded) {
|
|
653
|
+
return [];
|
|
654
|
+
}
|
|
655
|
+
try {
|
|
656
|
+
const parsed = JSON.parse(decoded);
|
|
657
|
+
return Array.isArray(parsed) ? parsed.filter((item) => Boolean(item && typeof item === "object" && !Array.isArray(item))) : [];
|
|
658
|
+
} catch {
|
|
659
|
+
return [];
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
var updateJsonListAttribute = ({
|
|
663
|
+
field,
|
|
664
|
+
index,
|
|
665
|
+
listAttr,
|
|
666
|
+
model,
|
|
667
|
+
value
|
|
668
|
+
}) => {
|
|
669
|
+
const attrs = model.getAttributes?.() || {};
|
|
670
|
+
const list = parseJsonArray(attrs[listAttr]);
|
|
671
|
+
if (!list[index]) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
list[index] = {
|
|
675
|
+
...list[index],
|
|
676
|
+
[field]: value
|
|
677
|
+
};
|
|
678
|
+
model.addAttributes?.({
|
|
679
|
+
[listAttr]: JSON.stringify(list)
|
|
680
|
+
});
|
|
681
|
+
};
|
|
682
|
+
var chooseAsset = (editor, currentSrc, callback) => {
|
|
683
|
+
const assetManager = editor?.AssetManager;
|
|
684
|
+
if (!assetManager?.open) {
|
|
685
|
+
const src = window.prompt("Image URL");
|
|
686
|
+
if (src) {
|
|
687
|
+
callback(src);
|
|
688
|
+
}
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
if (currentSrc) {
|
|
692
|
+
assetManager.add?.({
|
|
693
|
+
name: `Current image - ${currentSrc.split("/").pop() || currentSrc}`,
|
|
694
|
+
src: currentSrc,
|
|
695
|
+
type: "image"
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
assetManager.open({
|
|
699
|
+
select(asset) {
|
|
700
|
+
const src = typeof asset === "string" ? asset : asset && typeof asset === "object" && "get" in asset && typeof asset.get === "function" ? String(asset.get("src") || "") : asset && typeof asset === "object" && "src" in asset ? String(asset.src || "") : "";
|
|
701
|
+
if (src) {
|
|
702
|
+
callback(src);
|
|
703
|
+
}
|
|
704
|
+
assetManager.close?.();
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
};
|
|
708
|
+
var bindEditablePreview = (view, editor) => {
|
|
709
|
+
const root = view.el;
|
|
710
|
+
if (!root) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
root.querySelectorAll("[data-orion-edit-field]").forEach((element) => {
|
|
714
|
+
const field = element.dataset.orionEditField || "";
|
|
715
|
+
const listName = element.dataset.orionEditList || "";
|
|
716
|
+
const listIndex = Number(element.dataset.orionEditIndex);
|
|
717
|
+
const attrName = listName ? propToAttrName(listName) : propToAttrName(field);
|
|
718
|
+
const isImage = element.dataset.orionEditKind === "image" || element instanceof HTMLImageElement;
|
|
719
|
+
element.setAttribute("title", isImage ? "Click to replace image" : "Click and type to edit");
|
|
720
|
+
element.style.cursor = "text";
|
|
721
|
+
element.addEventListener("click", (event) => {
|
|
722
|
+
event.stopPropagation();
|
|
723
|
+
editor.select?.(view.model);
|
|
724
|
+
if (!isImage) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
element.style.cursor = "pointer";
|
|
728
|
+
const currentSrc = element instanceof HTMLImageElement ? element.currentSrc || element.src || "" : element.style.backgroundImage.replace(/^url\(["']?/, "").replace(/["']?\)$/, "");
|
|
729
|
+
chooseAsset(editor, currentSrc, (src) => {
|
|
730
|
+
if (listName && Number.isInteger(listIndex)) {
|
|
731
|
+
updateJsonListAttribute({
|
|
732
|
+
field,
|
|
733
|
+
index: listIndex,
|
|
734
|
+
listAttr: attrName,
|
|
735
|
+
model: view.model,
|
|
736
|
+
value: src
|
|
737
|
+
});
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
view.model.addAttributes?.({
|
|
741
|
+
[attrName]: src
|
|
742
|
+
});
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
if (isImage) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
element.setAttribute("contenteditable", "true");
|
|
749
|
+
element.setAttribute("spellcheck", "true");
|
|
750
|
+
const commit = () => {
|
|
751
|
+
const value = element.innerText.trim();
|
|
752
|
+
if (listName && Number.isInteger(listIndex)) {
|
|
753
|
+
updateJsonListAttribute({
|
|
754
|
+
field,
|
|
755
|
+
index: listIndex,
|
|
756
|
+
listAttr: attrName,
|
|
757
|
+
model: view.model,
|
|
758
|
+
value
|
|
759
|
+
});
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
view.model.addAttributes?.({
|
|
763
|
+
[attrName]: value
|
|
764
|
+
});
|
|
765
|
+
};
|
|
766
|
+
element.addEventListener("blur", commit);
|
|
767
|
+
element.addEventListener("keydown", (event) => {
|
|
768
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
769
|
+
event.preventDefault();
|
|
770
|
+
element.blur();
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
});
|
|
774
|
+
};
|
|
649
775
|
var registerProjectDynamicComponents = (editor, adapter) => {
|
|
650
776
|
const components = adapter?.components || {};
|
|
651
777
|
Object.keys(components).forEach((type) => {
|
|
@@ -689,6 +815,7 @@ var registerProjectDynamicComponents = (editor, adapter) => {
|
|
|
689
815
|
const props = propsFromAttributes(attributes);
|
|
690
816
|
this.model.components(previewForDefinition(definition, props));
|
|
691
817
|
lockPreviewChildren(this.model);
|
|
818
|
+
queueMicrotask(() => bindEditablePreview(this, editor));
|
|
692
819
|
}
|
|
693
820
|
}
|
|
694
821
|
});
|
|
@@ -739,10 +866,58 @@ var getRelationID = (value) => {
|
|
|
739
866
|
const id = value.id;
|
|
740
867
|
return typeof id === "number" || typeof id === "string" ? id : null;
|
|
741
868
|
};
|
|
869
|
+
var normalizeAssetSrc = (value) => {
|
|
870
|
+
const trimmed = value.trim();
|
|
871
|
+
if (!trimmed) {
|
|
872
|
+
return "";
|
|
873
|
+
}
|
|
874
|
+
if (/^(https?:)?\/\//i.test(trimmed) || trimmed.startsWith("/")) {
|
|
875
|
+
return trimmed;
|
|
876
|
+
}
|
|
877
|
+
return `/${trimmed}`;
|
|
878
|
+
};
|
|
879
|
+
var mediaDocImageCandidates = (doc) => {
|
|
880
|
+
const candidates = [];
|
|
881
|
+
if (doc.sizes && typeof doc.sizes === "object") {
|
|
882
|
+
Object.values(doc.sizes).forEach((size) => {
|
|
883
|
+
if (size?.url) {
|
|
884
|
+
candidates.push({ src: normalizeAssetSrc(size.url), width: size.width });
|
|
885
|
+
} else if (size?.filename) {
|
|
886
|
+
candidates.push({ src: `/api/media/file/${encodeURIComponent(size.filename)}`, width: size.width });
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
if (typeof doc.thumbnailURL === "string" && doc.thumbnailURL.length > 0) {
|
|
891
|
+
candidates.push({ src: normalizeAssetSrc(doc.thumbnailURL), width: 360 });
|
|
892
|
+
}
|
|
893
|
+
if (typeof doc.url === "string" && doc.url.length > 0) {
|
|
894
|
+
candidates.push({ src: normalizeAssetSrc(doc.url), width: doc.width });
|
|
895
|
+
}
|
|
896
|
+
if (typeof doc.filename === "string" && doc.filename.length > 0) {
|
|
897
|
+
candidates.push({ src: `/api/media/file/${encodeURIComponent(doc.filename)}`, width: doc.width });
|
|
898
|
+
}
|
|
899
|
+
return candidates.filter((candidate, index, all) => candidate.src && all.findIndex((item) => item.src === candidate.src) === index);
|
|
900
|
+
};
|
|
901
|
+
var pickMediaAssetSrc = (doc) => {
|
|
902
|
+
const candidates = mediaDocImageCandidates(doc);
|
|
903
|
+
if (candidates.length === 0) {
|
|
904
|
+
return "";
|
|
905
|
+
}
|
|
906
|
+
const absolute = candidates.find((candidate) => /^(https?:)?\/\//i.test(candidate.src));
|
|
907
|
+
if (absolute) {
|
|
908
|
+
return absolute.src;
|
|
909
|
+
}
|
|
910
|
+
const fullSize = candidates.find((candidate) => candidate.src === doc.url);
|
|
911
|
+
if (fullSize) {
|
|
912
|
+
return fullSize.src;
|
|
913
|
+
}
|
|
914
|
+
const widest = [...candidates].sort((left, right) => (right.width || 0) - (left.width || 0))[0];
|
|
915
|
+
return widest?.src || candidates[0]?.src || "";
|
|
916
|
+
};
|
|
742
917
|
var mediaDocToAsset = (doc) => {
|
|
743
918
|
const id = getRelationID(doc);
|
|
744
919
|
const filename = typeof doc.filename === "string" ? doc.filename : "";
|
|
745
|
-
const src =
|
|
920
|
+
const src = pickMediaAssetSrc(doc);
|
|
746
921
|
if (id === null || !src) {
|
|
747
922
|
return null;
|
|
748
923
|
}
|
|
@@ -754,6 +929,26 @@ var mediaDocToAsset = (doc) => {
|
|
|
754
929
|
type: "image"
|
|
755
930
|
};
|
|
756
931
|
};
|
|
932
|
+
var imageCanLoad = (src) => new Promise((resolve) => {
|
|
933
|
+
if (!src) {
|
|
934
|
+
resolve(false);
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
const image = new Image();
|
|
938
|
+
image.onload = () => resolve(true);
|
|
939
|
+
image.onerror = () => resolve(false);
|
|
940
|
+
image.src = src;
|
|
941
|
+
});
|
|
942
|
+
var pruneBrokenImageAssets = async (editor) => {
|
|
943
|
+
const assetManager = editor.AssetManager;
|
|
944
|
+
const existingAssets = assetManager.getAll?.() || [];
|
|
945
|
+
for (const asset of existingAssets) {
|
|
946
|
+
const src = typeof asset.get === "function" ? String(asset.get("src") || "") : "";
|
|
947
|
+
if (src && !await imageCanLoad(src)) {
|
|
948
|
+
assetManager.remove?.(asset);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
};
|
|
757
952
|
var extractUploadedMedia = (value) => {
|
|
758
953
|
const candidate = value && typeof value === "object" && "doc" in value ? value.doc : value;
|
|
759
954
|
if (!candidate || typeof candidate !== "object") {
|
|
@@ -768,7 +963,10 @@ var extractUploadedMedia = (value) => {
|
|
|
768
963
|
alt: typeof typed.alt === "string" ? typed.alt : "",
|
|
769
964
|
filename: typeof typed.filename === "string" ? typed.filename : "",
|
|
770
965
|
id,
|
|
771
|
-
|
|
966
|
+
sizes: typed.sizes && typeof typed.sizes === "object" ? typed.sizes : void 0,
|
|
967
|
+
thumbnailURL: typeof typed.thumbnailURL === "string" ? typed.thumbnailURL : "",
|
|
968
|
+
url: typeof typed.url === "string" ? typed.url : "",
|
|
969
|
+
width: typeof typed.width === "number" ? typed.width : void 0
|
|
772
970
|
};
|
|
773
971
|
};
|
|
774
972
|
var loadPayloadMediaAssets = async (editor) => {
|
|
@@ -780,8 +978,17 @@ var loadPayloadMediaAssets = async (editor) => {
|
|
|
780
978
|
return;
|
|
781
979
|
}
|
|
782
980
|
const json = await response.json();
|
|
783
|
-
const
|
|
784
|
-
|
|
981
|
+
const candidateAssets = (Array.isArray(json.docs) ? json.docs : []).map((doc) => mediaDocToAsset(doc)).filter((asset) => asset !== null);
|
|
982
|
+
const assets = [];
|
|
983
|
+
for (const asset of candidateAssets) {
|
|
984
|
+
if (await imageCanLoad(asset.src)) {
|
|
985
|
+
assets.push(asset);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
if (assets.length > 0) {
|
|
989
|
+
editor.AssetManager.add(assets);
|
|
990
|
+
}
|
|
991
|
+
await pruneBrokenImageAssets(editor);
|
|
785
992
|
};
|
|
786
993
|
var uploadPayloadMediaAssets = async (editor, files) => {
|
|
787
994
|
const fileArray = Array.from(files);
|
|
@@ -480,6 +480,7 @@ var decodeHtmlAttribute2 = (value) => {
|
|
|
480
480
|
return decoded;
|
|
481
481
|
};
|
|
482
482
|
var attrToPropName = (name) => name.replace(/^data-orion-/, "").replace(/^data-/, "").replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
483
|
+
var propToAttrName = (name) => `data-orion-${name.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)}`;
|
|
483
484
|
var propsFromAttributes = (attributes = {}) => {
|
|
484
485
|
const props = {};
|
|
485
486
|
Object.keys(attributes).forEach((name) => {
|
|
@@ -522,6 +523,131 @@ var lockPreviewChildren = (component) => {
|
|
|
522
523
|
lockPreviewChildren(child);
|
|
523
524
|
});
|
|
524
525
|
};
|
|
526
|
+
var parseJsonArray = (value) => {
|
|
527
|
+
const decoded = decodeHtmlAttribute2(value);
|
|
528
|
+
if (!decoded) {
|
|
529
|
+
return [];
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
const parsed = JSON.parse(decoded);
|
|
533
|
+
return Array.isArray(parsed) ? parsed.filter((item) => Boolean(item && typeof item === "object" && !Array.isArray(item))) : [];
|
|
534
|
+
} catch {
|
|
535
|
+
return [];
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
var updateJsonListAttribute = ({
|
|
539
|
+
field,
|
|
540
|
+
index,
|
|
541
|
+
listAttr,
|
|
542
|
+
model,
|
|
543
|
+
value
|
|
544
|
+
}) => {
|
|
545
|
+
const attrs = model.getAttributes?.() || {};
|
|
546
|
+
const list = parseJsonArray(attrs[listAttr]);
|
|
547
|
+
if (!list[index]) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
list[index] = {
|
|
551
|
+
...list[index],
|
|
552
|
+
[field]: value
|
|
553
|
+
};
|
|
554
|
+
model.addAttributes?.({
|
|
555
|
+
[listAttr]: JSON.stringify(list)
|
|
556
|
+
});
|
|
557
|
+
};
|
|
558
|
+
var chooseAsset = (editor, currentSrc, callback) => {
|
|
559
|
+
const assetManager = editor?.AssetManager;
|
|
560
|
+
if (!assetManager?.open) {
|
|
561
|
+
const src = window.prompt("Image URL");
|
|
562
|
+
if (src) {
|
|
563
|
+
callback(src);
|
|
564
|
+
}
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (currentSrc) {
|
|
568
|
+
assetManager.add?.({
|
|
569
|
+
name: `Current image - ${currentSrc.split("/").pop() || currentSrc}`,
|
|
570
|
+
src: currentSrc,
|
|
571
|
+
type: "image"
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
assetManager.open({
|
|
575
|
+
select(asset) {
|
|
576
|
+
const src = typeof asset === "string" ? asset : asset && typeof asset === "object" && "get" in asset && typeof asset.get === "function" ? String(asset.get("src") || "") : asset && typeof asset === "object" && "src" in asset ? String(asset.src || "") : "";
|
|
577
|
+
if (src) {
|
|
578
|
+
callback(src);
|
|
579
|
+
}
|
|
580
|
+
assetManager.close?.();
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
};
|
|
584
|
+
var bindEditablePreview = (view, editor) => {
|
|
585
|
+
const root = view.el;
|
|
586
|
+
if (!root) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
root.querySelectorAll("[data-orion-edit-field]").forEach((element) => {
|
|
590
|
+
const field = element.dataset.orionEditField || "";
|
|
591
|
+
const listName = element.dataset.orionEditList || "";
|
|
592
|
+
const listIndex = Number(element.dataset.orionEditIndex);
|
|
593
|
+
const attrName = listName ? propToAttrName(listName) : propToAttrName(field);
|
|
594
|
+
const isImage = element.dataset.orionEditKind === "image" || element instanceof HTMLImageElement;
|
|
595
|
+
element.setAttribute("title", isImage ? "Click to replace image" : "Click and type to edit");
|
|
596
|
+
element.style.cursor = "text";
|
|
597
|
+
element.addEventListener("click", (event) => {
|
|
598
|
+
event.stopPropagation();
|
|
599
|
+
editor.select?.(view.model);
|
|
600
|
+
if (!isImage) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
element.style.cursor = "pointer";
|
|
604
|
+
const currentSrc = element instanceof HTMLImageElement ? element.currentSrc || element.src || "" : element.style.backgroundImage.replace(/^url\(["']?/, "").replace(/["']?\)$/, "");
|
|
605
|
+
chooseAsset(editor, currentSrc, (src) => {
|
|
606
|
+
if (listName && Number.isInteger(listIndex)) {
|
|
607
|
+
updateJsonListAttribute({
|
|
608
|
+
field,
|
|
609
|
+
index: listIndex,
|
|
610
|
+
listAttr: attrName,
|
|
611
|
+
model: view.model,
|
|
612
|
+
value: src
|
|
613
|
+
});
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
view.model.addAttributes?.({
|
|
617
|
+
[attrName]: src
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
if (isImage) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
element.setAttribute("contenteditable", "true");
|
|
625
|
+
element.setAttribute("spellcheck", "true");
|
|
626
|
+
const commit = () => {
|
|
627
|
+
const value = element.innerText.trim();
|
|
628
|
+
if (listName && Number.isInteger(listIndex)) {
|
|
629
|
+
updateJsonListAttribute({
|
|
630
|
+
field,
|
|
631
|
+
index: listIndex,
|
|
632
|
+
listAttr: attrName,
|
|
633
|
+
model: view.model,
|
|
634
|
+
value
|
|
635
|
+
});
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
view.model.addAttributes?.({
|
|
639
|
+
[attrName]: value
|
|
640
|
+
});
|
|
641
|
+
};
|
|
642
|
+
element.addEventListener("blur", commit);
|
|
643
|
+
element.addEventListener("keydown", (event) => {
|
|
644
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
645
|
+
event.preventDefault();
|
|
646
|
+
element.blur();
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
};
|
|
525
651
|
var registerProjectDynamicComponents = (editor, adapter) => {
|
|
526
652
|
const components = adapter?.components || {};
|
|
527
653
|
Object.keys(components).forEach((type) => {
|
|
@@ -565,6 +691,7 @@ var registerProjectDynamicComponents = (editor, adapter) => {
|
|
|
565
691
|
const props = propsFromAttributes(attributes);
|
|
566
692
|
this.model.components(previewForDefinition(definition, props));
|
|
567
693
|
lockPreviewChildren(this.model);
|
|
694
|
+
queueMicrotask(() => bindEditablePreview(this, editor));
|
|
568
695
|
}
|
|
569
696
|
}
|
|
570
697
|
});
|
|
@@ -615,10 +742,58 @@ var getRelationID = (value) => {
|
|
|
615
742
|
const id = value.id;
|
|
616
743
|
return typeof id === "number" || typeof id === "string" ? id : null;
|
|
617
744
|
};
|
|
745
|
+
var normalizeAssetSrc = (value) => {
|
|
746
|
+
const trimmed = value.trim();
|
|
747
|
+
if (!trimmed) {
|
|
748
|
+
return "";
|
|
749
|
+
}
|
|
750
|
+
if (/^(https?:)?\/\//i.test(trimmed) || trimmed.startsWith("/")) {
|
|
751
|
+
return trimmed;
|
|
752
|
+
}
|
|
753
|
+
return `/${trimmed}`;
|
|
754
|
+
};
|
|
755
|
+
var mediaDocImageCandidates = (doc) => {
|
|
756
|
+
const candidates = [];
|
|
757
|
+
if (doc.sizes && typeof doc.sizes === "object") {
|
|
758
|
+
Object.values(doc.sizes).forEach((size) => {
|
|
759
|
+
if (size?.url) {
|
|
760
|
+
candidates.push({ src: normalizeAssetSrc(size.url), width: size.width });
|
|
761
|
+
} else if (size?.filename) {
|
|
762
|
+
candidates.push({ src: `/api/media/file/${encodeURIComponent(size.filename)}`, width: size.width });
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
if (typeof doc.thumbnailURL === "string" && doc.thumbnailURL.length > 0) {
|
|
767
|
+
candidates.push({ src: normalizeAssetSrc(doc.thumbnailURL), width: 360 });
|
|
768
|
+
}
|
|
769
|
+
if (typeof doc.url === "string" && doc.url.length > 0) {
|
|
770
|
+
candidates.push({ src: normalizeAssetSrc(doc.url), width: doc.width });
|
|
771
|
+
}
|
|
772
|
+
if (typeof doc.filename === "string" && doc.filename.length > 0) {
|
|
773
|
+
candidates.push({ src: `/api/media/file/${encodeURIComponent(doc.filename)}`, width: doc.width });
|
|
774
|
+
}
|
|
775
|
+
return candidates.filter((candidate, index, all) => candidate.src && all.findIndex((item) => item.src === candidate.src) === index);
|
|
776
|
+
};
|
|
777
|
+
var pickMediaAssetSrc = (doc) => {
|
|
778
|
+
const candidates = mediaDocImageCandidates(doc);
|
|
779
|
+
if (candidates.length === 0) {
|
|
780
|
+
return "";
|
|
781
|
+
}
|
|
782
|
+
const absolute = candidates.find((candidate) => /^(https?:)?\/\//i.test(candidate.src));
|
|
783
|
+
if (absolute) {
|
|
784
|
+
return absolute.src;
|
|
785
|
+
}
|
|
786
|
+
const fullSize = candidates.find((candidate) => candidate.src === doc.url);
|
|
787
|
+
if (fullSize) {
|
|
788
|
+
return fullSize.src;
|
|
789
|
+
}
|
|
790
|
+
const widest = [...candidates].sort((left, right) => (right.width || 0) - (left.width || 0))[0];
|
|
791
|
+
return widest?.src || candidates[0]?.src || "";
|
|
792
|
+
};
|
|
618
793
|
var mediaDocToAsset = (doc) => {
|
|
619
794
|
const id = getRelationID(doc);
|
|
620
795
|
const filename = typeof doc.filename === "string" ? doc.filename : "";
|
|
621
|
-
const src =
|
|
796
|
+
const src = pickMediaAssetSrc(doc);
|
|
622
797
|
if (id === null || !src) {
|
|
623
798
|
return null;
|
|
624
799
|
}
|
|
@@ -630,6 +805,26 @@ var mediaDocToAsset = (doc) => {
|
|
|
630
805
|
type: "image"
|
|
631
806
|
};
|
|
632
807
|
};
|
|
808
|
+
var imageCanLoad = (src) => new Promise((resolve) => {
|
|
809
|
+
if (!src) {
|
|
810
|
+
resolve(false);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
const image = new Image();
|
|
814
|
+
image.onload = () => resolve(true);
|
|
815
|
+
image.onerror = () => resolve(false);
|
|
816
|
+
image.src = src;
|
|
817
|
+
});
|
|
818
|
+
var pruneBrokenImageAssets = async (editor) => {
|
|
819
|
+
const assetManager = editor.AssetManager;
|
|
820
|
+
const existingAssets = assetManager.getAll?.() || [];
|
|
821
|
+
for (const asset of existingAssets) {
|
|
822
|
+
const src = typeof asset.get === "function" ? String(asset.get("src") || "") : "";
|
|
823
|
+
if (src && !await imageCanLoad(src)) {
|
|
824
|
+
assetManager.remove?.(asset);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
};
|
|
633
828
|
var extractUploadedMedia = (value) => {
|
|
634
829
|
const candidate = value && typeof value === "object" && "doc" in value ? value.doc : value;
|
|
635
830
|
if (!candidate || typeof candidate !== "object") {
|
|
@@ -644,7 +839,10 @@ var extractUploadedMedia = (value) => {
|
|
|
644
839
|
alt: typeof typed.alt === "string" ? typed.alt : "",
|
|
645
840
|
filename: typeof typed.filename === "string" ? typed.filename : "",
|
|
646
841
|
id,
|
|
647
|
-
|
|
842
|
+
sizes: typed.sizes && typeof typed.sizes === "object" ? typed.sizes : void 0,
|
|
843
|
+
thumbnailURL: typeof typed.thumbnailURL === "string" ? typed.thumbnailURL : "",
|
|
844
|
+
url: typeof typed.url === "string" ? typed.url : "",
|
|
845
|
+
width: typeof typed.width === "number" ? typed.width : void 0
|
|
648
846
|
};
|
|
649
847
|
};
|
|
650
848
|
var loadPayloadMediaAssets = async (editor) => {
|
|
@@ -656,8 +854,17 @@ var loadPayloadMediaAssets = async (editor) => {
|
|
|
656
854
|
return;
|
|
657
855
|
}
|
|
658
856
|
const json = await response.json();
|
|
659
|
-
const
|
|
660
|
-
|
|
857
|
+
const candidateAssets = (Array.isArray(json.docs) ? json.docs : []).map((doc) => mediaDocToAsset(doc)).filter((asset) => asset !== null);
|
|
858
|
+
const assets = [];
|
|
859
|
+
for (const asset of candidateAssets) {
|
|
860
|
+
if (await imageCanLoad(asset.src)) {
|
|
861
|
+
assets.push(asset);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
if (assets.length > 0) {
|
|
865
|
+
editor.AssetManager.add(assets);
|
|
866
|
+
}
|
|
867
|
+
await pruneBrokenImageAssets(editor);
|
|
661
868
|
};
|
|
662
869
|
var uploadPayloadMediaAssets = async (editor, files) => {
|
|
663
870
|
const fileArray = Array.from(files);
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED