@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
302 lines (301 loc) • 9.88 kB
JavaScript
// packages/editor/src/components/media-categories/index.js
import { __, sprintf, _x } from "@wordpress/i18n";
import { dispatch, resolveSelect, select, subscribe } from "@wordpress/data";
import { decodeEntities } from "@wordpress/html-entities";
import { store as coreStore } from "@wordpress/core-data";
var getExternalLink = (url, text) => `<a ${getExternalLinkAttributes(url)}>${text}</a>`;
var getExternalLinkAttributes = (url) => `href="${url}" target="_blank" rel="noopener"`;
var getOpenverseLicense = (license, licenseVersion) => {
let licenseName = license.trim();
if (license !== "pdm") {
licenseName = license.toUpperCase().replace("SAMPLING", "Sampling");
}
if (licenseVersion) {
licenseName += ` ${licenseVersion}`;
}
if (!["pdm", "cc0"].includes(license)) {
licenseName = `CC ${licenseName}`;
}
return licenseName;
};
var getOpenverseCaption = (item) => {
const {
title,
foreign_landing_url: foreignLandingUrl,
creator,
creator_url: creatorUrl,
license,
license_version: licenseVersion,
license_url: licenseUrl
} = item;
const fullLicense = getOpenverseLicense(license, licenseVersion);
const _creator = decodeEntities(creator);
let _caption;
if (_creator) {
_caption = title ? sprintf(
// translators: %1s: Title of a media work from Openverse; %2$s: Name of the work's creator; %3s: Work's licence e.g: "CC0 1.0".
_x('"%1$s" by %2$s/ %3$s', "caption"),
getExternalLink(
foreignLandingUrl,
decodeEntities(title)
),
creatorUrl ? getExternalLink(creatorUrl, _creator) : _creator,
licenseUrl ? getExternalLink(
`${licenseUrl}?ref=openverse`,
fullLicense
) : fullLicense
) : sprintf(
// translators: %1s: Link attributes for a given Openverse media work; %2s: Name of the work's creator; %3s: Works's licence e.g: "CC0 1.0".
_x("<a %1$s>Work</a> by %2$s/ %3$s", "caption"),
getExternalLinkAttributes(foreignLandingUrl),
creatorUrl ? getExternalLink(creatorUrl, _creator) : _creator,
licenseUrl ? getExternalLink(
`${licenseUrl}?ref=openverse`,
fullLicense
) : fullLicense
);
} else {
_caption = title ? sprintf(
// translators: %1s: Title of a media work from Openverse; %2s: Work's licence e.g: "CC0 1.0".
_x('"%1$s"/ %2$s', "caption"),
getExternalLink(
foreignLandingUrl,
decodeEntities(title)
),
licenseUrl ? getExternalLink(
`${licenseUrl}?ref=openverse`,
fullLicense
) : fullLicense
) : sprintf(
// translators: %1s: Link attributes for a given Openverse media work; %2s: Works's licence e.g: "CC0 1.0".
_x("<a %1$s>Work</a>/ %2$s", "caption"),
getExternalLinkAttributes(foreignLandingUrl),
licenseUrl ? getExternalLink(
`${licenseUrl}?ref=openverse`,
fullLicense
) : fullLicense
);
}
return _caption.replace(/\s{2}/g, " ");
};
var getCoreMediaQuery = (query = {}) => ({
...query,
orderBy: !!query?.search ? "relevance" : "date"
});
var coreMediaFetch = async (query = {}) => {
const finalQuery = getCoreMediaQuery(query);
const records = await resolveSelect(coreStore).getEntityRecords(
"postType",
"attachment",
finalQuery
);
const totalItems = select(coreStore).getEntityRecordsTotalItems(
"postType",
"attachment",
finalQuery
);
const totalPages = select(coreStore).getEntityRecordsTotalPages(
"postType",
"attachment",
finalQuery
);
return {
mediaItems: records.map((record) => ({
...record,
alt: record.alt_text,
url: record.source_url,
previewUrl: record.media_details?.sizes?.medium?.source_url,
caption: record.caption?.raw
})),
totalItems,
totalPages
};
};
var getAttachedImagesQuery = (postId, query = {}) => ({
...query,
media_type: "image",
parent: postId
});
var normalizePostId = (postId) => {
const parsedPostId = typeof postId === "number" ? postId : Number(postId);
return Number.isInteger(parsedPostId) && parsedPostId > 0 ? parsedPostId : void 0;
};
var saveAttachmentParent = (attachmentId, postId) => (
// `throwOnError` so a failed REST write rejects (rather than being silently
// swallowed), letting the attach/detach handlers surface an error notice
// instead of a false success.
dispatch(coreStore).saveEntityRecord(
"postType",
"attachment",
{
id: attachmentId,
post: postId
},
{ throwOnError: true }
)
);
var getMediaItemType = (mediaItem) => mediaItem?.media_type || mediaItem?.mime_type?.split("/")[0] || mediaItem?.type;
var getImageAttachmentIds = (mediaItems) => [
...new Set(
(Array.isArray(mediaItems) ? mediaItems : [mediaItems]).filter(
(mediaItem) => getMediaItemType(mediaItem) === "image"
).map((mediaItem) => mediaItem?.id).filter(Boolean)
)
];
var invalidateAttachedImagesQueries = (postId, query = {}) => {
const { invalidateResolution } = dispatch(coreStore);
invalidateResolution("getEntityRecords", [
"postType",
"attachment",
getCoreMediaQuery(getAttachedImagesQuery(postId, query))
]);
};
var subscribeToMediaInvalidation = (args, onChange) => {
const isResolved = () => select(coreStore).hasFinishedResolution("getEntityRecords", args);
let wasResolved = isResolved();
return subscribe(() => {
const nowResolved = isResolved();
if (wasResolved && !nowResolved) {
onChange();
}
wasResolved = nowResolved;
}, coreStore);
};
var createCoreMediaCategory = ({ getQuery, ...category }) => ({
...category,
async fetch(query = {}) {
return coreMediaFetch(getQuery(query));
},
subscribe(onChange, query = {}) {
return subscribeToMediaInvalidation(
[
"postType",
"attachment",
getCoreMediaQuery(getQuery(query))
],
onChange
);
}
});
var getAttachedImagesCategory = (postId, typeLabel) => createCoreMediaCategory({
name: "attached-images",
labels: {
name: __("Attached images"),
search_items: __("Search attachments")
},
mediaType: "image",
getQuery: (query) => getAttachedImagesQuery(postId, query),
// The post type's singular label (e.g. "Page"), threaded through so the
// shared panel can word its attach/detach copy for the current post type.
postTypeLabel: typeLabel,
// Empty-state message. Providing this also keeps the source in the tab
// list when it has no items, so it stays discoverable and the first
// image can be attached even with none yet.
emptyMessage: typeLabel ? sprintf(
// translators: %s: Name of the post type e.g: "Page".
__("No images attached to this %s."),
typeLabel
) : __("No images attached to this post."),
async attach(mediaItems) {
const attachmentIds = getImageAttachmentIds(mediaItems);
await Promise.all(
attachmentIds.map(
(attachmentId) => saveAttachmentParent(attachmentId, postId)
)
);
return attachmentIds.length;
},
async detach(mediaItem) {
await saveAttachmentParent(mediaItem.id, 0);
},
invalidate(query = {}) {
invalidateAttachedImagesQueries(postId, query);
}
});
var inserterMediaCategories = [
createCoreMediaCategory({
name: "images",
labels: {
name: __("Images"),
search_items: __("Search images")
},
mediaType: "image",
getQuery: (query) => ({ ...query, media_type: "image" })
}),
createCoreMediaCategory({
name: "videos",
labels: {
name: __("Videos"),
search_items: __("Search videos")
},
mediaType: "video",
getQuery: (query) => ({ ...query, media_type: "video" })
}),
createCoreMediaCategory({
name: "audio",
labels: {
name: __("Audio"),
search_items: __("Search audio")
},
mediaType: "audio",
getQuery: (query) => ({ ...query, media_type: "audio" })
}),
{
name: "openverse",
labels: {
name: __("Openverse"),
search_items: __("Search Openverse")
},
mediaType: "image",
async fetch(query = {}) {
const defaultArgs = {
mature: false,
excluded_source: "flickr,inaturalist,wikimedia",
license: "pdm,cc0"
};
const finalQuery = { ...query, ...defaultArgs };
const mapFromInserterMediaRequest = {
per_page: "page_size",
search: "q"
};
const url = new URL("https://api.openverse.org/v1/images/");
Object.entries(finalQuery).forEach(([key, value]) => {
const queryKey = mapFromInserterMediaRequest[key] || key;
url.searchParams.set(queryKey, value);
});
const response = await window.fetch(url, {
headers: {
"User-Agent": "WordPress/inserter-media-fetch"
}
});
const jsonResponse = await response.json();
const results = jsonResponse.results;
return results.map((result) => ({
...result,
// This is a temp solution for better titles, until Openverse API
// completes the cleaning up of some titles of their upstream data.
title: result.title?.toLowerCase().startsWith("file:") ? result.title.slice(5) : result.title,
sourceId: result.id,
id: void 0,
caption: getOpenverseCaption(result),
previewUrl: result.thumbnail
}));
},
getReportUrl: ({ sourceId }) => `https://wordpress.org/openverse/image/${sourceId}/report/`,
isExternalResource: true
}
];
function getInserterMediaCategories(postId, viewablePostTypeLabel) {
const currentPostId = normalizePostId(postId);
if (!currentPostId || !viewablePostTypeLabel) {
return inserterMediaCategories;
}
return [
getAttachedImagesCategory(currentPostId, viewablePostTypeLabel),
...inserterMediaCategories
];
}
export {
getInserterMediaCategories as default
};
//# sourceMappingURL=index.mjs.map