UNPKG

@wordpress/block-library

Version:
479 lines (410 loc) • 18.4 kB
"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