"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = usePasteStyles;
var _element = require("@wordpress/element");
var _blocks = require("@wordpress/blocks");
var _data = require("@wordpress/data");
var _notices = require("@wordpress/notices");
var _i18n = require("@wordpress/i18n");
var _store = require("../../store");
var _supports = require("../../hooks/supports");
/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

/**
 * Determine if the copied text looks like serialized blocks or not.
 * Since plain text will always get parsed into a freeform block,
 * we check that if the parsed blocks is anything other than that.
 *
 * @param {string} text The copied text.
 * @return {boolean} True if the text looks like serialized blocks, false otherwise.
 */
function hasSerializedBlocks(text) {
  try {
    const blocks = (0, _blocks.parse)(text, {
      __unstableSkipMigrationLogs: true,
      __unstableSkipAutop: true
    });
    if (blocks.length === 1 && blocks[0].name === 'core/freeform') {
      // It's likely that the text is just plain text and not serialized blocks.
      return false;
    }
    return true;
  } catch (err) {
    // Parsing error, the text is not serialized blocks.
    // (Even though that it technically won't happen)
    return false;
  }
}

/**
 * Style attributes are attributes being added in `block-editor/src/hooks/*`.
 * (Except for some unrelated to style like `anchor` or `settings`.)
 * They generally represent the default block supports.
 */
const STYLE_ATTRIBUTES = {
  align: _supports.hasAlignSupport,
  borderColor: nameOrType => (0, _supports.hasBorderSupport)(nameOrType, 'color'),
  backgroundColor: _supports.hasBackgroundColorSupport,
  textAlign: _supports.hasTextAlignSupport,
  textColor: _supports.hasTextColorSupport,
  gradient: _supports.hasGradientSupport,
  className: _supports.hasCustomClassNameSupport,
  fontFamily: _supports.hasFontFamilySupport,
  fontSize: _supports.hasFontSizeSupport,
  layout: _supports.hasLayoutSupport,
  style: _supports.hasStyleSupport
};

/**
 * Get the "style attributes" from a given block to a target block.
 *
 * @param {WPBlock} sourceBlock The source block.
 * @param {WPBlock} targetBlock The target block.
 * @return {Object} the filtered attributes object.
 */
function getStyleAttributes(sourceBlock, targetBlock) {
  return Object.entries(STYLE_ATTRIBUTES).reduce((attributes, [attributeKey, hasSupport]) => {
    // Only apply the attribute if both blocks support it.
    if (hasSupport(sourceBlock.name) && hasSupport(targetBlock.name)) {
      // Override attributes that are not present in the block to their defaults.
      attributes[attributeKey] = sourceBlock.attributes[attributeKey];
    }
    return attributes;
  }, {});
}

/**
 * Update the target blocks with style attributes recursively.
 *
 * @param {WPBlock[]} targetBlocks          The target blocks to be updated.
 * @param {WPBlock[]} sourceBlocks          The source blocks to get th style attributes from.
 * @param {Function}  updateBlockAttributes The function to update the attributes.
 */
function recursivelyUpdateBlockAttributes(targetBlocks, sourceBlocks, updateBlockAttributes) {
  for (let index = 0; index < Math.min(sourceBlocks.length, targetBlocks.length); index += 1) {
    updateBlockAttributes(targetBlocks[index].clientId, getStyleAttributes(sourceBlocks[index], targetBlocks[index]));
    recursivelyUpdateBlockAttributes(targetBlocks[index].innerBlocks, sourceBlocks[index].innerBlocks, updateBlockAttributes);
  }
}

/**
 * A hook to return a pasteStyles event function for handling pasting styles to blocks.
 *
 * @return {Function} A function to update the styles to the blocks.
 */
function usePasteStyles() {
  const registry = (0, _data.useRegistry)();
  const {
    updateBlockAttributes
  } = (0, _data.useDispatch)(_store.store);
  const {
    createSuccessNotice,
    createWarningNotice,
    createErrorNotice
  } = (0, _data.useDispatch)(_notices.store);
  return (0, _element.useCallback)(async targetBlocks => {
    let html = '';
    try {
      // `http:` sites won't have the clipboard property on navigator.
      // (with the exception of localhost.)
      if (!window.navigator.clipboard) {
        createErrorNotice((0, _i18n.__)('Unable to paste styles. This feature is only available on secure (https) sites in supporting browsers.'), {
          type: 'snackbar'
        });
        return;
      }
      html = await window.navigator.clipboard.readText();
    } catch (error) {
      // Possibly the permission is denied.
      createErrorNotice((0, _i18n.__)('Unable to paste styles. Please allow browser clipboard permissions before continuing.'), {
        type: 'snackbar'
      });
      return;
    }

    // Abort if the copied text is empty or doesn't look like serialized blocks.
    if (!html || !hasSerializedBlocks(html)) {
      createWarningNotice((0, _i18n.__)("Unable to paste styles. Block styles couldn't be found within the copied content."), {
        type: 'snackbar'
      });
      return;
    }
    const copiedBlocks = (0, _blocks.parse)(html);
    if (copiedBlocks.length === 1) {
      // Apply styles of the block to all the target blocks.
      registry.batch(() => {
        recursivelyUpdateBlockAttributes(targetBlocks, targetBlocks.map(() => copiedBlocks[0]), updateBlockAttributes);
      });
    } else {
      registry.batch(() => {
        recursivelyUpdateBlockAttributes(targetBlocks, copiedBlocks, updateBlockAttributes);
      });
    }
    if (targetBlocks.length === 1) {
      const title = (0, _blocks.getBlockType)(targetBlocks[0].name)?.title;
      createSuccessNotice((0, _i18n.sprintf)(
      // Translators: Name of the block being pasted, e.g. "Paragraph".
      (0, _i18n.__)('Pasted styles to %s.'), title), {
        type: 'snackbar'
      });
    } else {
      createSuccessNotice((0, _i18n.sprintf)(
      // Translators: The number of the blocks.
      (0, _i18n.__)('Pasted styles to %d blocks.'), targetBlocks.length), {
        type: 'snackbar'
      });
    }
  }, [registry.batch, updateBlockAttributes, createSuccessNotice, createWarningNotice, createErrorNotice]);
}
//# sourceMappingURL=index.js.map