@wordpress/block-library
Version:
Block library for the WordPress editor.
293 lines (292 loc) • 9.81 kB
JavaScript
// packages/block-library/src/image/use-open-image-media-editor-modal.js
import { store as coreStore } from "@wordpress/core-data";
import {
privateApis as blockEditorPrivateApis,
store as blockEditorStore
} from "@wordpress/block-editor";
import { __unstableStripHTML as stripHTML } from "@wordpress/dom";
import { useRegistry, useSelect } from "@wordpress/data";
import { useCallback, useEffect, useRef } from "@wordpress/element";
import { unlock } from "../lock-unlock.mjs";
import {
DEFAULT_MEDIA_SIZE_SLUG,
LINK_DESTINATION_ATTACHMENT,
LINK_DESTINATION_MEDIA
} from "./constants.mjs";
function normalizeImageBlockCaption(caption) {
if (typeof caption !== "string") {
return "";
}
const textContent = stripHTML(caption).trim();
if (!textContent) {
return "";
}
return caption.replace(/\n/g, "<br>");
}
function getAttachmentCaption(attachment) {
const caption = attachment?.caption;
if (typeof caption === "string") {
return normalizeImageBlockCaption(caption);
}
if (caption && typeof caption === "object" && Object.hasOwn(caption, "raw")) {
return normalizeImageBlockCaption(caption.raw);
}
return void 0;
}
function getImageBlockMetadataFromAttachment(attachment) {
return {
alt: typeof attachment?.alt_text === "string" ? attachment.alt_text : attachment?.alt || "",
caption: getAttachmentCaption(attachment)
};
}
function normalizeMetadataAttribute(value) {
return value || "";
}
function getSyncedImageBlockAttributes(currentAttributes, originalAttachment, updatedAttachment) {
if (!originalAttachment || !updatedAttachment) {
return {};
}
const originalMetadata = getImageBlockMetadataFromAttachment(originalAttachment);
const updatedMetadata = getImageBlockMetadataFromAttachment(updatedAttachment);
const syncedAttributes = {};
const normalizedCurrentAlt = normalizeMetadataAttribute(
currentAttributes.alt
);
if (originalMetadata.alt !== updatedMetadata.alt && (normalizedCurrentAlt === originalMetadata.alt || !normalizedCurrentAlt)) {
syncedAttributes.alt = updatedMetadata.alt;
}
const normalizedCurrentCaption = normalizeMetadataAttribute(
currentAttributes.caption
);
if (originalMetadata.caption !== void 0 && updatedMetadata.caption !== void 0 && originalMetadata.caption !== updatedMetadata.caption && (normalizedCurrentCaption === originalMetadata.caption || !normalizedCurrentCaption)) {
syncedAttributes.caption = updatedMetadata.caption || void 0;
}
return syncedAttributes;
}
function getNewAttachmentSizeAttributes(sizeSlug, attachment) {
const sizes = attachment.media_details?.sizes;
if (!sizeSlug || sizeSlug === DEFAULT_MEDIA_SIZE_SLUG || !sizes) {
return void 0;
}
const sizeUrl = sizes[sizeSlug]?.source_url;
if (sizeUrl) {
return { url: sizeUrl };
}
const fullUrl = attachment.source_url ?? sizes.full?.source_url;
return fullUrl ? { url: fullUrl, sizeSlug: DEFAULT_MEDIA_SIZE_SLUG } : void 0;
}
function getNewAttachmentLinkAttributes(linkDestination, attachment) {
if (linkDestination === LINK_DESTINATION_MEDIA) {
return attachment.source_url ? { href: attachment.source_url } : void 0;
}
if (linkDestination === LINK_DESTINATION_ATTACHMENT) {
return attachment.link ? { href: attachment.link } : void 0;
}
return void 0;
}
function getNewAttachmentImageBlockAttributes(blockAttributes, attachment) {
if (!attachment) {
return void 0;
}
return {
...getNewAttachmentSizeAttributes(
blockAttributes.sizeSlug,
attachment
),
...getNewAttachmentLinkAttributes(
blockAttributes.linkDestination,
attachment
)
};
}
var { openMediaEditorModalKey } = unlock(blockEditorPrivateApis);
function getAttachmentFallbackForEmptyBlockMetadata({ alt, caption }) {
const attachment = {};
if (!alt) {
attachment.alt_text = "";
}
if (!caption?.toString()) {
attachment.caption = "";
}
return Object.keys(attachment).length ? attachment : void 0;
}
function hasKnownAttachmentMetadata(attachment) {
if (!attachment) {
return false;
}
const hasKnownAlt = typeof attachment.alt_text === "string" || typeof attachment.alt === "string";
const hasKnownCaption = getImageBlockMetadataFromAttachment(attachment).caption !== void 0;
return hasKnownAlt && hasKnownCaption;
}
function useOpenImageMediaEditorModal({
attributes,
setAttributes,
onClose,
onUrlChange
}) {
const { id, url, alt, caption, sizeSlug, linkDestination } = attributes;
const registry = useRegistry();
const openMediaEditorModal = useSelect(
(select) => select(blockEditorStore).getSettings()[openMediaEditorModalKey],
[]
);
const blockAttributesRef = useRef({
id,
url,
alt,
caption: caption?.toString(),
sizeSlug,
linkDestination
});
const mediaEditorMetadataBaselineRef = useRef();
const mediaEditorMetadataSyncRequestRef = useRef(0);
useEffect(() => {
blockAttributesRef.current = {
id,
url,
alt,
caption: caption?.toString(),
sizeSlug,
linkDestination
};
}, [alt, caption, id, linkDestination, sizeSlug, url]);
const getCachedAttachmentRecord = useCallback(
(attachmentId) => registry.select(coreStore).getEditedEntityRecord(
"postType",
"attachment",
attachmentId
),
[registry]
);
const resolveAttachmentRecord = useCallback(
async (attachmentId) => {
const resolveSelect = registry.resolveSelect(coreStore);
try {
return await resolveSelect.getEntityRecord(
"postType",
"attachment",
attachmentId
);
} catch {
return void 0;
}
},
[registry]
);
const resolveFreshAttachmentRecord = useCallback(
async (attachmentId) => {
const { invalidateResolution } = registry.dispatch(coreStore);
invalidateResolution("getEntityRecord", [
"postType",
"attachment",
attachmentId
]);
return resolveAttachmentRecord(attachmentId);
},
[registry, resolveAttachmentRecord]
);
const handleMediaUpdate = useCallback(
async ({ id: newId, url: newUrl }) => {
if (typeof newId !== "number") {
return;
}
const originalAttachment = mediaEditorMetadataBaselineRef.current;
mediaEditorMetadataBaselineRef.current = void 0;
const syncRequest = ++mediaEditorMetadataSyncRequestRef.current;
const nextAttributes = {};
const currentBlockAttributes = blockAttributesRef.current;
const isNewAttachment = newId !== currentBlockAttributes.id;
if (isNewAttachment) {
nextAttributes.id = newId;
nextAttributes.url = newUrl ?? currentBlockAttributes.url;
if (nextAttributes.url !== currentBlockAttributes.url) {
onUrlChange?.(nextAttributes.url);
}
blockAttributesRef.current = {
...blockAttributesRef.current,
id: nextAttributes.id,
url: nextAttributes.url
};
}
if (originalAttachment || isNewAttachment) {
const resolvedAttachment = await resolveFreshAttachmentRecord(newId);
if (syncRequest !== mediaEditorMetadataSyncRequestRef.current) {
return;
}
const attachmentRecord = resolvedAttachment ?? getCachedAttachmentRecord(newId);
const latestBlockAttributes = blockAttributesRef.current;
if (originalAttachment) {
const resolvedMetadataAttributes = getSyncedImageBlockAttributes(
latestBlockAttributes,
originalAttachment,
attachmentRecord
);
if (Object.keys(resolvedMetadataAttributes).length) {
Object.assign(
nextAttributes,
resolvedMetadataAttributes
);
}
}
if (isNewAttachment) {
const derivedAttributes = getNewAttachmentImageBlockAttributes(
latestBlockAttributes,
attachmentRecord
);
if (derivedAttributes) {
Object.assign(nextAttributes, derivedAttributes);
if (derivedAttributes.url && derivedAttributes.url !== latestBlockAttributes.url) {
onUrlChange?.(derivedAttributes.url);
}
}
}
}
if (Object.keys(nextAttributes).length) {
blockAttributesRef.current = {
...blockAttributesRef.current,
...nextAttributes
};
setAttributes(nextAttributes);
}
},
[
getCachedAttachmentRecord,
onUrlChange,
resolveFreshAttachmentRecord,
setAttributes
]
);
const openImageMediaEditorModal = useCallback(async () => {
if (!id || !openMediaEditorModal) {
return;
}
const cachedAttachmentRecord = getCachedAttachmentRecord(id);
const fallbackAttachmentRecord = getAttachmentFallbackForEmptyBlockMetadata(
blockAttributesRef.current
);
const resolvedAttachmentRecord = hasKnownAttachmentMetadata(
cachedAttachmentRecord
) ? void 0 : await resolveAttachmentRecord(id);
mediaEditorMetadataBaselineRef.current = resolvedAttachmentRecord || (hasKnownAttachmentMetadata(cachedAttachmentRecord) ? cachedAttachmentRecord : fallbackAttachmentRecord) || cachedAttachmentRecord;
openMediaEditorModal({
id,
onUpdate: handleMediaUpdate,
onClose
});
}, [
getCachedAttachmentRecord,
handleMediaUpdate,
id,
onClose,
openMediaEditorModal,
resolveAttachmentRecord
]);
return id && openMediaEditorModal ? openImageMediaEditorModal : void 0;
}
export {
getImageBlockMetadataFromAttachment,
getNewAttachmentImageBlockAttributes,
getSyncedImageBlockAttributes,
useOpenImageMediaEditorModal
};
//# sourceMappingURL=use-open-image-media-editor-modal.mjs.map