"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = GalleryEdit;
var _clsx = _interopRequireDefault(require("clsx"));
var _components = require("@wordpress/components");
var _blockEditor = require("@wordpress/block-editor");
var _element = require("@wordpress/element");
var _i18n = require("@wordpress/i18n");
var _data = require("@wordpress/data");
var _primitives = require("@wordpress/primitives");
var _blocks = require("@wordpress/blocks");
var _blob = require("@wordpress/blob");
var _notices = require("@wordpress/notices");
var _icons = require("@wordpress/icons");
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"));
var _jsxRuntime = require("react/jsx-runtime");
/**
 * External dependencies
 */

/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

const MAX_COLUMNS = 8;
const linkOptions = [{
  icon: _icons.customLink,
  label: (0, _i18n.__)('Link images to attachment pages'),
  value: _constants.LINK_DESTINATION_ATTACHMENT,
  noticeText: (0, _i18n.__)('Attachment Pages')
}, {
  icon: _icons.image,
  label: (0, _i18n.__)('Link images to media files'),
  value: _constants.LINK_DESTINATION_MEDIA,
  noticeText: (0, _i18n.__)('Media Files')
}, {
  icon: _icons.linkOff,
  label: (0, _i18n._x)('None', 'Media item link option'),
  value: _constants.LINK_DESTINATION_NONE,
  noticeText: (0, _i18n.__)('None')
}];
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'
} : {};
const DEFAULT_BLOCK = {
  name: 'core/image'
};
const EMPTY_ARRAY = [];
function GalleryEdit(props) {
  const {
    setAttributes,
    attributes,
    className,
    clientId,
    isSelected,
    insertBlocksAfter,
    isContentLocked,
    onFocus
  } = props;
  const {
    columns,
    imageCrop,
    randomOrder,
    linkTarget,
    linkTo,
    sizeSlug
  } = attributes;
  const {
    __unstableMarkNextChangeAsNotPersistent,
    replaceInnerBlocks,
    updateBlockAttributes,
    selectBlock
  } = (0, _data.useDispatch)(_blockEditor.store);
  const {
    createSuccessNotice,
    createErrorNotice
  } = (0, _data.useDispatch)(_notices.store);
  const {
    getBlock,
    getSettings,
    innerBlockImages,
    blockWasJustInserted,
    multiGallerySelection
  } = (0, _data.useSelect)(select => {
    var _getBlock$innerBlocks;
    const {
      getBlockName,
      getMultiSelectedBlockClientIds,
      getSettings: _getSettings,
      getBlock: _getBlock,
      wasBlockJustInserted
    } = select(_blockEditor.store);
    const multiSelectedClientIds = getMultiSelectedBlockClientIds();
    return {
      getBlock: _getBlock,
      getSettings: _getSettings,
      innerBlockImages: (_getBlock$innerBlocks = _getBlock(clientId)?.innerBlocks) !== null && _getBlock$innerBlocks !== void 0 ? _getBlock$innerBlocks : EMPTY_ARRAY,
      blockWasJustInserted: wasBlockJustInserted(clientId, 'inserter_menu'),
      multiGallerySelection: multiSelectedClientIds.length && multiSelectedClientIds.every(_clientId => getBlockName(_clientId) === 'core/gallery')
    };
  }, [clientId]);
  const images = (0, _element.useMemo)(() => 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?.forEach(newImage => {
      // Update the images data without creating new undo levels.
      __unstableMarkNextChangeAsNotPersistent();
      updateBlockAttributes(newImage.clientId, {
        ...buildImageAttributes(newImage.attributes),
        id: newImage.id,
        align: undefined
      });
    });
  }, [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) {
    const image = imageAttributes.id ? imageData.find(({
      id
    }) => id === imageAttributes.id) : null;
    let newClassName;
    if (imageAttributes.className && imageAttributes.className !== '') {
      newClassName = imageAttributes.className;
    }
    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?.linkDestination),
      ...newLinkTarget,
      className: newClassName,
      sizeSlug,
      caption: imageAttributes.caption || image.caption?.raw,
      alt: imageAttributes.alt || image.alt_text
    };
  }
  function isValidFileType(file) {
    // It's necessary to retrieve the media type from the raw image data for already-uploaded images on native.
    const nativeFileData = _element.Platform.isNative && file.id ? imageData.find(({
      id
    }) => id === file.id) : null;
    const mediaTypeSelector = nativeFileData ? nativeFileData?.media_type : file.type;
    return ALLOWED_MEDIA_TYPES.some(mediaType => mediaTypeSelector?.indexOf(mediaType) === 0) || file.blob;
  }
  function updateImages(selectedImages) {
    const newFileUploads = Object.prototype.toString.call(selectedImages) === '[object FileList]';
    const imageArray = newFileUploads ? Array.from(selectedImages).map(file => {
      if (!file.url) {
        return {
          blob: (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 {
          blob: file.blob || (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,
        blob: image.blob,
        url: image.url,
        caption: image.caption,
        alt: image.alt
      });
    });
    replaceInnerBlocks(clientId, existingImageBlocks.concat(newBlocks).sort((a, b) => newOrderMap[a.attributes.id] - newOrderMap[b.attributes.id]));

    // Select the first block to scroll into view when new blocks are added.
    if (newBlocks?.length > 0) {
      selectBlock(newBlocks[0].clientId);
    }
  }
  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 ? imageData.find(({
        id
      }) => 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.noticeText), {
      id: 'gallery-attributes-linkTo',
      type: 'snackbar'
    });
  }
  function setColumnsNumber(value) {
    setAttributes({
      columns: value
    });
  }
  function toggleImageCrop() {
    setAttributes({
      imageCrop: !imageCrop
    });
  }
  function toggleRandomOrder() {
    setAttributes({
      randomOrder: !randomOrder
    });
  }
  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 ? imageData.find(({
        id
      }) => 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) {
      __unstableMarkNextChangeAsNotPersistent();
      setAttributes({
        linkTo: window?.wp?.media?.view?.settings?.defaultProps?.link || _constants.LINK_DESTINATION_NONE
      });
    }
  }, [linkTo]);
  const hasImages = !!images.length;
  const hasImageIds = hasImages && images.some(image => !!image.id);
  const imagesUploading = images.some(img => !_element.Platform.isNative ? !img.id && img.url?.indexOf('blob:') === 0 : img.url?.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 && blockWasJustInserted,
      onFocus
    }
  });
  const mediaPlaceholder = /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.MediaPlaceholder, {
    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, _clsx.default)(className, 'has-nested-images')
  });
  const nativeInnerBlockProps = _element.Platform.isNative && {
    marginHorizontal: 0,
    marginVertical: 0
  };
  const innerBlocksProps = (0, _blockEditor.useInnerBlocksProps)(blockProps, {
    defaultBlock: DEFAULT_BLOCK,
    directInsert: true,
    orientation: 'horizontal',
    renderAppender: false,
    ...nativeInnerBlockProps
  });
  if (!hasImages) {
    return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_primitives.View, {
      ...innerBlocksProps,
      children: [innerBlocksProps.children, mediaPlaceholder]
    });
  }
  const hasLinkTo = linkTo && linkTo !== 'none';
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
      children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.PanelBody, {
        title: (0, _i18n.__)('Settings'),
        children: [images.length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RangeControl, {
          __nextHasNoMarginBottom: true,
          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,
          __next40pxDefaultSize: true
        }), imageSizeOptions?.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.SelectControl, {
          __nextHasNoMarginBottom: true,
          label: (0, _i18n.__)('Resolution'),
          help: (0, _i18n.__)('Select the size of the source images.'),
          value: sizeSlug,
          options: imageSizeOptions,
          onChange: updateImagesSize,
          hideCancelButton: true,
          size: "__unstable-large"
        }), _element.Platform.isNative ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.SelectControl, {
          __nextHasNoMarginBottom: true,
          label: (0, _i18n.__)('Link'),
          value: linkTo,
          onChange: setLinkTo,
          options: linkOptions,
          hideCancelButton: true,
          size: "__unstable-large"
        }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
          __nextHasNoMarginBottom: true,
          label: (0, _i18n.__)('Crop images to fit'),
          checked: !!imageCrop,
          onChange: toggleImageCrop
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
          __nextHasNoMarginBottom: true,
          label: (0, _i18n.__)('Randomize order'),
          checked: !!randomOrder,
          onChange: toggleRandomOrder
        }), hasLinkTo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
          __nextHasNoMarginBottom: true,
          label: (0, _i18n.__)('Open images in new tab'),
          checked: linkTarget === '_blank',
          onChange: toggleOpenInNewTab
        }), _element.Platform.isWeb && !imageSizeOptions && hasImageIds && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.BaseControl, {
          className: "gallery-image-sizes",
          __nextHasNoMarginBottom: true,
          children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.BaseControl.VisualLabel, {
            children: (0, _i18n.__)('Resolution')
          }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_primitives.View, {
            className: "gallery-image-sizes__loading",
            children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {}), (0, _i18n.__)('Loading options…')]
          })]
        })]
      })
    }), _element.Platform.isWeb ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, {
      group: "block",
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarDropdownMenu, {
        icon: _icons.link,
        label: (0, _i18n.__)('Link'),
        children: ({
          onClose
        }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuGroup, {
          children: linkOptions.map(linkItem => {
            const isOptionSelected = linkTo === linkItem.value;
            return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MenuItem, {
              isSelected: isOptionSelected,
              className: (0, _clsx.default)('components-dropdown-menu__menu-item', {
                'is-active': isOptionSelected
              }),
              iconPosition: "left",
              icon: linkItem.icon,
              onClick: () => {
                setLinkTo(linkItem.value);
                onClose();
              },
              role: "menuitemradio",
              children: linkItem.label
            }, linkItem.value);
          })
        })
      })
    }) : null, _element.Platform.isWeb && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
      children: [!multiGallerySelection && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, {
        group: "other",
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_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
        })
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_gapStyles.default, {
        blockGap: attributes.style?.spacing?.blockGap,
        clientId: clientId
      })]
    }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_gallery.default, {
      ...props,
      isContentLocked: isContentLocked,
      images: images,
      mediaPlaceholder: !hasImages || _element.Platform.isNative ? mediaPlaceholder : undefined,
      blockProps: innerBlocksProps,
      insertBlocksAfter: insertBlocksAfter,
      multiGallerySelection: multiGallerySelection
    })]
  });
}
//# sourceMappingURL=edit.js.map