@wordpress/block-library
Version:
Block library for the WordPress editor.
479 lines (410 loc) • 18.4 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _element = require("@wordpress/element");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _classnames = _interopRequireDefault(require("classnames"));
var _lodash = require("lodash");
var _compose = require("@wordpress/compose");
var _components = require("@wordpress/components");
var _blockEditor = require("@wordpress/block-editor");
var _i18n = require("@wordpress/i18n");
var _data = require("@wordpress/data");
var _viewport = require("@wordpress/viewport");
var _primitives = require("@wordpress/primitives");
var _blocks = require("@wordpress/blocks");
var _blob = require("@wordpress/blob");
var _notices = require("@wordpress/notices");
var _sharedIcon = require("./shared-icon");
var _shared = require("./shared");
var _utils = require("./utils");
var _utils2 = require("../image/utils");
var _gallery = _interopRequireDefault(require("./gallery"));
var _constants = require("./constants");
var _useImageSizes = _interopRequireDefault(require("./use-image-sizes"));
var _useGetNewImages = _interopRequireDefault(require("./use-get-new-images"));
var _useGetMedia = _interopRequireDefault(require("./use-get-media"));
var _gapStyles = _interopRequireDefault(require("./gap-styles"));
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
const MAX_COLUMNS = 8;
const linkOptions = [{
value: _constants.LINK_DESTINATION_ATTACHMENT,
label: (0, _i18n.__)('Attachment Page')
}, {
value: _constants.LINK_DESTINATION_MEDIA,
label: (0, _i18n.__)('Media File')
}, {
value: _constants.LINK_DESTINATION_NONE,
label: (0, _i18n._x)('None', 'Media item link option')
}];
const ALLOWED_MEDIA_TYPES = ['image'];
const PLACEHOLDER_TEXT = _element.Platform.isNative ? (0, _i18n.__)('ADD MEDIA') : (0, _i18n.__)('Drag images, upload new ones or select files from your library.');
const MOBILE_CONTROL_PROPS_RANGE_CONTROL = _element.Platform.isNative ? {
type: 'stepper'
} : {};
function GalleryEdit(props) {
var _attributes$style, _attributes$style$spa;
const {
setAttributes,
attributes,
className,
clientId,
isSelected,
insertBlocksAfter
} = props;
const {
columns,
imageCrop,
linkTarget,
linkTo,
sizeSlug
} = attributes;
const {
__unstableMarkNextChangeAsNotPersistent,
replaceInnerBlocks,
updateBlockAttributes,
selectBlock,
clearSelectedBlock
} = (0, _data.useDispatch)(_blockEditor.store);
const {
createSuccessNotice,
createErrorNotice
} = (0, _data.useDispatch)(_notices.store);
const {
getBlock,
getSettings,
preferredStyle
} = (0, _data.useSelect)(select => {
var _preferredStyleVariat;
const settings = select(_blockEditor.store).getSettings();
const preferredStyleVariations = settings.__experimentalPreferredStyleVariations;
return {
getBlock: select(_blockEditor.store).getBlock,
getSettings: select(_blockEditor.store).getSettings,
preferredStyle: preferredStyleVariations === null || preferredStyleVariations === void 0 ? void 0 : (_preferredStyleVariat = preferredStyleVariations.value) === null || _preferredStyleVariat === void 0 ? void 0 : _preferredStyleVariat['core/image']
};
}, []);
const innerBlockImages = (0, _data.useSelect)(select => {
var _select$getBlock;
return (_select$getBlock = select(_blockEditor.store).getBlock(clientId)) === null || _select$getBlock === void 0 ? void 0 : _select$getBlock.innerBlocks;
}, [clientId]);
const wasBlockJustInserted = (0, _data.useSelect)(select => {
return select(_blockEditor.store).wasBlockJustInserted(clientId, 'inserter_menu');
}, [clientId]);
const images = (0, _element.useMemo)(() => innerBlockImages === null || innerBlockImages === void 0 ? void 0 : innerBlockImages.map(block => ({
clientId: block.clientId,
id: block.attributes.id,
url: block.attributes.url,
attributes: block.attributes,
fromSavedContent: Boolean(block.originalContent)
})), [innerBlockImages]);
const imageData = (0, _useGetMedia.default)(innerBlockImages);
const newImages = (0, _useGetNewImages.default)(images, imageData);
(0, _element.useEffect)(() => {
newImages === null || newImages === void 0 ? void 0 : newImages.forEach(newImage => {
// Update the images data without creating new undo levels.
__unstableMarkNextChangeAsNotPersistent();
updateBlockAttributes(newImage.clientId, { ...buildImageAttributes(newImage.attributes),
id: newImage.id,
align: undefined
});
});
if ((newImages === null || newImages === void 0 ? void 0 : newImages.length) > 0) {
clearSelectedBlock();
}
}, [newImages]);
const imageSizeOptions = (0, _useImageSizes.default)(imageData, isSelected, getSettings);
/**
* Determines the image attributes that should be applied to an image block
* after the gallery updates.
*
* The gallery will receive the full collection of images when a new image
* is added. As a result we need to reapply the image's original settings if
* it already existed in the gallery. If the image is in fact new, we need
* to apply the gallery's current settings to the image.
*
* @param {Object} imageAttributes Media object for the actual image.
* @return {Object} Attributes to set on the new image block.
*/
function buildImageAttributes(imageAttributes) {
var _image$caption;
const image = imageAttributes.id ? (0, _lodash.find)(imageData, {
id: imageAttributes.id
}) : null;
let newClassName;
if (imageAttributes.className && imageAttributes.className !== '') {
newClassName = imageAttributes.className;
} else {
newClassName = preferredStyle ? `is-style-${preferredStyle}` : undefined;
}
let newLinkTarget;
if (imageAttributes.linkTarget || imageAttributes.rel) {
// When transformed from image blocks, the link destination and rel attributes are inherited.
newLinkTarget = {
linkTarget: imageAttributes.linkTarget,
rel: imageAttributes.rel
};
} else {
// When an image is added, update the link destination and rel attributes according to the gallery settings
newLinkTarget = (0, _utils2.getUpdatedLinkTargetSettings)(linkTarget, attributes);
}
return { ...(0, _shared.pickRelevantMediaFiles)(image, sizeSlug),
...(0, _utils.getHrefAndDestination)(image, linkTo, imageAttributes === null || imageAttributes === void 0 ? void 0 : imageAttributes.linkDestination),
...newLinkTarget,
className: newClassName,
sizeSlug,
caption: imageAttributes.caption || ((_image$caption = image.caption) === null || _image$caption === void 0 ? void 0 : _image$caption.raw),
alt: imageAttributes.alt || image.alt_text
};
}
function isValidFileType(file) {
var _file$url;
return ALLOWED_MEDIA_TYPES.some(mediaType => {
var _file$type;
return ((_file$type = file.type) === null || _file$type === void 0 ? void 0 : _file$type.indexOf(mediaType)) === 0;
}) || ((_file$url = file.url) === null || _file$url === void 0 ? void 0 : _file$url.indexOf('blob:')) === 0;
}
function updateImages(selectedImages) {
const newFileUploads = Object.prototype.toString.call(selectedImages) === '[object FileList]';
const imageArray = newFileUploads ? Array.from(selectedImages).map(file => {
if (!file.url) {
return (0, _shared.pickRelevantMediaFiles)({
url: (0, _blob.createBlobURL)(file)
});
}
return file;
}) : selectedImages;
if (!imageArray.every(isValidFileType)) {
createErrorNotice((0, _i18n.__)('If uploading to a gallery all files need to be image formats'), {
id: 'gallery-upload-invalid-file',
type: 'snackbar'
});
}
const processedImages = imageArray.filter(file => file.url || isValidFileType(file)).map(file => {
if (!file.url) {
return (0, _shared.pickRelevantMediaFiles)({
url: (0, _blob.createBlobURL)(file)
});
}
return file;
}); // Because we are reusing existing innerImage blocks any reordering
// done in the media library will be lost so we need to reapply that ordering
// once the new image blocks are merged in with existing.
const newOrderMap = processedImages.reduce((result, image, index) => (result[image.id] = index, result), {});
const existingImageBlocks = !newFileUploads ? innerBlockImages.filter(block => processedImages.find(img => img.id === block.attributes.id)) : innerBlockImages;
const newImageList = processedImages.filter(img => !existingImageBlocks.find(existingImg => img.id === existingImg.attributes.id));
const newBlocks = newImageList.map(image => {
return (0, _blocks.createBlock)('core/image', {
id: image.id,
url: image.url,
caption: image.caption,
alt: image.alt
});
});
if ((newBlocks === null || newBlocks === void 0 ? void 0 : newBlocks.length) > 0) {
selectBlock(newBlocks[0].clientId);
}
replaceInnerBlocks(clientId, existingImageBlocks.concat(newBlocks).sort((a, b) => newOrderMap[a.attributes.id] - newOrderMap[b.attributes.id]));
}
function onUploadError(message) {
createErrorNotice(message, {
type: 'snackbar'
});
}
function setLinkTo(value) {
setAttributes({
linkTo: value
});
const changedAttributes = {};
const blocks = [];
getBlock(clientId).innerBlocks.forEach(block => {
blocks.push(block.clientId);
const image = block.attributes.id ? (0, _lodash.find)(imageData, {
id: block.attributes.id
}) : null;
changedAttributes[block.clientId] = (0, _utils.getHrefAndDestination)(image, value);
});
updateBlockAttributes(blocks, changedAttributes, true);
const linkToText = [...linkOptions].find(linkType => linkType.value === value);
createSuccessNotice((0, _i18n.sprintf)(
/* translators: %s: image size settings */
(0, _i18n.__)('All gallery image links updated to: %s'), linkToText.label), {
id: 'gallery-attributes-linkTo',
type: 'snackbar'
});
}
function setColumnsNumber(value) {
setAttributes({
columns: value
});
}
function toggleImageCrop() {
setAttributes({
imageCrop: !imageCrop
});
}
function getImageCropHelp(checked) {
return checked ? (0, _i18n.__)('Thumbnails are cropped to align.') : (0, _i18n.__)('Thumbnails are not cropped.');
}
function toggleOpenInNewTab(openInNewTab) {
const newLinkTarget = openInNewTab ? '_blank' : undefined;
setAttributes({
linkTarget: newLinkTarget
});
const changedAttributes = {};
const blocks = [];
getBlock(clientId).innerBlocks.forEach(block => {
blocks.push(block.clientId);
changedAttributes[block.clientId] = (0, _utils2.getUpdatedLinkTargetSettings)(newLinkTarget, block.attributes);
});
updateBlockAttributes(blocks, changedAttributes, true);
const noticeText = openInNewTab ? (0, _i18n.__)('All gallery images updated to open in new tab') : (0, _i18n.__)('All gallery images updated to not open in new tab');
createSuccessNotice(noticeText, {
id: 'gallery-attributes-openInNewTab',
type: 'snackbar'
});
}
function updateImagesSize(newSizeSlug) {
setAttributes({
sizeSlug: newSizeSlug
});
const changedAttributes = {};
const blocks = [];
getBlock(clientId).innerBlocks.forEach(block => {
blocks.push(block.clientId);
const image = block.attributes.id ? (0, _lodash.find)(imageData, {
id: block.attributes.id
}) : null;
changedAttributes[block.clientId] = (0, _utils2.getImageSizeAttributes)(image, newSizeSlug);
});
updateBlockAttributes(blocks, changedAttributes, true);
const imageSize = imageSizeOptions.find(size => size.value === newSizeSlug);
createSuccessNotice((0, _i18n.sprintf)(
/* translators: %s: image size settings */
(0, _i18n.__)('All gallery image sizes updated to: %s'), imageSize.label), {
id: 'gallery-attributes-sizeSlug',
type: 'snackbar'
});
}
(0, _element.useEffect)(() => {
// linkTo attribute must be saved so blocks don't break when changing image_default_link_type in options.php.
if (!linkTo) {
var _window, _window$wp, _window$wp$media, _window$wp$media$view, _window$wp$media$view2, _window$wp$media$view3;
__unstableMarkNextChangeAsNotPersistent();
setAttributes({
linkTo: ((_window = window) === null || _window === void 0 ? void 0 : (_window$wp = _window.wp) === null || _window$wp === void 0 ? void 0 : (_window$wp$media = _window$wp.media) === null || _window$wp$media === void 0 ? void 0 : (_window$wp$media$view = _window$wp$media.view) === null || _window$wp$media$view === void 0 ? void 0 : (_window$wp$media$view2 = _window$wp$media$view.settings) === null || _window$wp$media$view2 === void 0 ? void 0 : (_window$wp$media$view3 = _window$wp$media$view2.defaultProps) === null || _window$wp$media$view3 === void 0 ? void 0 : _window$wp$media$view3.link) || _constants.LINK_DESTINATION_NONE
});
}
}, [linkTo]);
const hasImages = !!images.length;
const hasImageIds = hasImages && images.some(image => !!image.id);
const imagesUploading = images.some(img => {
var _img$url, _img$url2;
return !_element.Platform.isNative ? !img.id && ((_img$url = img.url) === null || _img$url === void 0 ? void 0 : _img$url.indexOf('blob:')) === 0 : ((_img$url2 = img.url) === null || _img$url2 === void 0 ? void 0 : _img$url2.indexOf('file:')) === 0;
}); // MediaPlaceholder props are different between web and native hence, we provide a platform-specific set.
const mediaPlaceholderProps = _element.Platform.select({
web: {
addToGallery: false,
disableMediaButtons: imagesUploading,
value: {}
},
native: {
addToGallery: hasImageIds,
isAppender: hasImages,
disableMediaButtons: hasImages && !isSelected || imagesUploading,
value: hasImageIds ? images : {},
autoOpenMediaUpload: !hasImages && isSelected && wasBlockJustInserted
}
});
const mediaPlaceholder = (0, _element.createElement)(_blockEditor.MediaPlaceholder, (0, _extends2.default)({
handleUpload: false,
icon: _sharedIcon.sharedIcon,
labels: {
title: (0, _i18n.__)('Gallery'),
instructions: PLACEHOLDER_TEXT
},
onSelect: updateImages,
accept: "image/*",
allowedTypes: ALLOWED_MEDIA_TYPES,
multiple: true,
onError: onUploadError
}, mediaPlaceholderProps));
const blockProps = (0, _blockEditor.useBlockProps)({
className: (0, _classnames.default)(className, 'has-nested-images')
});
if (!hasImages) {
return (0, _element.createElement)(_primitives.View, blockProps, mediaPlaceholder);
}
const hasLinkTo = linkTo && linkTo !== 'none';
return (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_blockEditor.InspectorControls, null, (0, _element.createElement)(_components.PanelBody, {
title: (0, _i18n.__)('Settings')
}, images.length > 1 && (0, _element.createElement)(_components.RangeControl, (0, _extends2.default)({
label: (0, _i18n.__)('Columns'),
value: columns ? columns : (0, _shared.defaultColumnsNumber)(images.length),
onChange: setColumnsNumber,
min: 1,
max: Math.min(MAX_COLUMNS, images.length)
}, MOBILE_CONTROL_PROPS_RANGE_CONTROL, {
required: true
})), (0, _element.createElement)(_components.ToggleControl, {
label: (0, _i18n.__)('Crop images'),
checked: !!imageCrop,
onChange: toggleImageCrop,
help: getImageCropHelp
}), (0, _element.createElement)(_components.SelectControl, {
label: (0, _i18n.__)('Link to'),
value: linkTo,
onChange: setLinkTo,
options: linkOptions,
hideCancelButton: true
}), hasLinkTo && (0, _element.createElement)(_components.ToggleControl, {
label: (0, _i18n.__)('Open in new tab'),
checked: linkTarget === '_blank',
onChange: toggleOpenInNewTab
}), (imageSizeOptions === null || imageSizeOptions === void 0 ? void 0 : imageSizeOptions.length) > 0 && (0, _element.createElement)(_components.SelectControl, {
label: (0, _i18n.__)('Image size'),
value: sizeSlug,
options: imageSizeOptions,
onChange: updateImagesSize,
hideCancelButton: true
}), _element.Platform.isWeb && !imageSizeOptions && hasImageIds && (0, _element.createElement)(_components.BaseControl, {
className: 'gallery-image-sizes'
}, (0, _element.createElement)(_components.BaseControl.VisualLabel, null, (0, _i18n.__)('Image size')), (0, _element.createElement)(_primitives.View, {
className: 'gallery-image-sizes__loading'
}, (0, _element.createElement)(_components.Spinner, null), (0, _i18n.__)('Loading options…'))))), (0, _element.createElement)(_blockEditor.BlockControls, {
group: "other"
}, (0, _element.createElement)(_blockEditor.MediaReplaceFlow, {
allowedTypes: ALLOWED_MEDIA_TYPES,
accept: "image/*",
handleUpload: false,
onSelect: updateImages,
name: (0, _i18n.__)('Add'),
multiple: true,
mediaIds: images.filter(image => image.id).map(image => image.id),
addToGallery: hasImageIds
})), _element.Platform.isWeb && (0, _element.createElement)(_gapStyles.default, {
blockGap: (_attributes$style = attributes.style) === null || _attributes$style === void 0 ? void 0 : (_attributes$style$spa = _attributes$style.spacing) === null || _attributes$style$spa === void 0 ? void 0 : _attributes$style$spa.blockGap,
clientId: clientId
}), (0, _element.createElement)(_gallery.default, (0, _extends2.default)({}, props, {
images: images,
mediaPlaceholder: !hasImages || _element.Platform.isNative ? mediaPlaceholder : undefined,
blockProps: blockProps,
insertBlocksAfter: insertBlocksAfter
})));
}
var _default = (0, _compose.compose)([(0, _viewport.withViewportMatch)({
isNarrow: '< small'
})])(GalleryEdit);
exports.default = _default;
//# sourceMappingURL=edit.js.map