"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.ExperimentalEditorProvider = void 0;
var _reactNative = require("react-native");
var _memize = _interopRequireDefault(require("memize"));
var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
var _reactNativeBridge = _interopRequireWildcard(require("@wordpress/react-native-bridge"));
var _element = require("@wordpress/element");
var _wordcount = require("@wordpress/wordcount");
var _blocks = require("@wordpress/blocks");
var _data = require("@wordpress/data");
var _compose = require("@wordpress/compose");
var _hooks = require("@wordpress/hooks");
var _blockEditor = require("@wordpress/block-editor");
var _blockLibrary = require("@wordpress/block-library");
var _i18n = require("@wordpress/i18n");
var _editor = require("@wordpress/editor");
var _notices = require("@wordpress/notices");
var _coreData = require("@wordpress/core-data");
var _index = _interopRequireDefault(require("./index.js"));
var _postTitle = require("../post-title");
var _jsxRuntime = require("react/jsx-runtime");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
 * External dependencies
 */

/**
 * WordPress dependencies
 */

const postTypeEntities = [{
  name: 'post',
  baseURL: '/wp/v2/posts'
}, {
  name: 'page',
  baseURL: '/wp/v2/pages'
}, {
  name: 'attachment',
  baseURL: '/wp/v2/media',
  baseURLParams: {
    context: 'edit'
  }
}, {
  name: 'wp_block',
  baseURL: '/wp/v2/blocks'
}].map(postTypeEntity => ({
  kind: 'postType',
  ...postTypeEntity,
  transientEdits: {
    blocks: true,
    selection: true
  },
  mergedEdits: {
    meta: true
  },
  rawAttributes: ['title', 'excerpt', 'content']
}));

/**
 * Internal dependencies
 */

class NativeEditorProvider extends _element.Component {
  constructor() {
    super(...arguments);

    // Keep a local reference to `post` to detect changes.
    this.post = this.props.post;
    this.props.addEntities(postTypeEntities);
    this.props.receiveEntityRecords('postType', this.post.type, this.post);
    this.onHardwareBackPress = this.onHardwareBackPress.bind(this);
    this.onContentUpdate = this.onContentUpdate.bind(this);
    this.getEditorSettings = (0, _memize.default)((settings, capabilities) => ({
      ...settings,
      capabilities
    }), {
      maxSize: 1
    });
    this.state = {
      isHelpVisible: false
    };
  }
  componentDidMount() {
    const {
      capabilities,
      createErrorNotice,
      locale,
      hostAppNamespace,
      updateEditorSettings,
      updateBlockEditorSettings
    } = this.props;
    updateEditorSettings({
      capabilities,
      ...this.getThemeColors(this.props),
      locale,
      hostAppNamespace
    });
    this.subscriptionParentGetHtml = (0, _reactNativeBridge.subscribeParentGetHtml)(() => {
      this.serializeToNativeAction();
    });
    this.subscriptionParentToggleHTMLMode = (0, _reactNativeBridge.subscribeParentToggleHTMLMode)(() => {
      this.toggleMode();
    });
    this.subscriptionParentSetTitle = (0, _reactNativeBridge.subscribeSetTitle)(payload => {
      this.props.editTitle(payload.title);
    });
    this.subscriptionParentUpdateHtml = (0, _reactNativeBridge.subscribeUpdateHtml)(payload => {
      this.updateHtmlAction(payload.html);
    });
    this.subscriptionParentReplaceBlock = (0, _reactNativeBridge.subscribeReplaceBlock)(payload => {
      this.replaceBlockAction(payload.html, payload.clientId);
    });
    this.subscriptionParentMediaAppend = (0, _reactNativeBridge.subscribeMediaAppend)(payload => {
      const blockName = 'core/' + payload.mediaType;
      const blockType = (0, _blocks.getBlockType)(blockName);
      if (blockType && blockType?.name) {
        const newBlock = (0, _blocks.createBlock)(blockType.name, {
          id: payload.mediaId,
          [payload.mediaType === 'image' ? 'url' : 'src']: payload.mediaUrl
        });
        const indexAfterSelected = this.props.selectedBlockIndex + 1;
        const insertionIndex = indexAfterSelected || this.props.blockCount;
        this.props.insertBlock(newBlock, insertionIndex);
      } else {
        createErrorNotice((0, _i18n.__)('File type not supported as a media file.'));
      }
    });
    this.subscriptionParentUpdateEditorSettings = (0, _reactNativeBridge.subscribeUpdateEditorSettings)(({
      ...editorSettings
    }) => {
      updateEditorSettings(this.getThemeColors(editorSettings));
    });
    this.subscriptionParentUpdateCapabilities = (0, _reactNativeBridge.subscribeUpdateCapabilities)(payload => {
      this.updateCapabilitiesAction(payload);
    });
    this.subscriptionParentShowNotice = (0, _reactNativeBridge.subscribeShowNotice)(payload => {
      this.props.createSuccessNotice(payload.message);
    });
    this.subscriptionParentShowEditorHelp = (0, _reactNativeBridge.subscribeShowEditorHelp)(() => {
      this.setState({
        isHelpVisible: true
      });
    });
    this.hardwareBackPressListener = _reactNative.BackHandler.addEventListener('hardwareBackPress', this.onHardwareBackPress);
    this.subscriptionOnContentUpdate = (0, _reactNativeBridge.subscribeToContentUpdate)(data => {
      this.onContentUpdate(data);
    });

    // Request current block impressions from native app.
    (0, _reactNativeBridge.requestBlockTypeImpressions)(storedImpressions => {
      const impressions = {
        ..._blockLibrary.NEW_BLOCK_TYPES,
        ...storedImpressions
      };

      // Persist impressions to JavaScript store.
      updateBlockEditorSettings({
        impressions
      });

      // Persist impressions to native store if they do not include latest
      // `NEW_BLOCK_TYPES` configuration.
      const storedImpressionKeys = Object.keys(storedImpressions);
      const storedImpressionsCurrent = Object.keys(_blockLibrary.NEW_BLOCK_TYPES).every(newKey => storedImpressionKeys.includes(newKey));
      if (!storedImpressionsCurrent) {
        (0, _reactNativeBridge.setBlockTypeImpressions)(impressions);
      }
    });
  }
  componentWillUnmount() {
    if (this.subscriptionParentGetHtml) {
      this.subscriptionParentGetHtml.remove();
    }
    if (this.subscriptionParentToggleHTMLMode) {
      this.subscriptionParentToggleHTMLMode.remove();
    }
    if (this.subscriptionParentSetTitle) {
      this.subscriptionParentSetTitle.remove();
    }
    if (this.subscriptionParentUpdateHtml) {
      this.subscriptionParentUpdateHtml.remove();
    }
    if (this.subscriptionParentReplaceBlock) {
      this.subscriptionParentReplaceBlock.remove();
    }
    if (this.subscriptionParentMediaAppend) {
      this.subscriptionParentMediaAppend.remove();
    }
    if (this.subscriptionParentUpdateEditorSettings) {
      this.subscriptionParentUpdateEditorSettings.remove();
    }
    if (this.subscriptionParentUpdateCapabilities) {
      this.subscriptionParentUpdateCapabilities.remove();
    }
    if (this.subscriptionParentShowNotice) {
      this.subscriptionParentShowNotice.remove();
    }
    if (this.subscriptionParentShowEditorHelp) {
      this.subscriptionParentShowEditorHelp.remove();
    }
    if (this.hardwareBackPressListener) {
      this.hardwareBackPressListener.remove();
    }
    if (this.subscriptionOnContentUpdate) {
      this.subscriptionOnContentUpdate.remove();
    }
  }
  getThemeColors({
    rawStyles,
    rawFeatures
  }) {
    const {
      defaultEditorColors,
      defaultEditorGradients
    } = this.props;
    if (rawStyles && rawFeatures) {
      return (0, _blockEditor.getGlobalStyles)(rawStyles, rawFeatures);
    }
    return (0, _blockEditor.getColorsAndGradients)(defaultEditorColors, defaultEditorGradients, rawFeatures);
  }
  componentDidUpdate(prevProps) {
    if (!prevProps.isReady && this.props.isReady) {
      const blocks = this.props.blocks;
      const isUnsupportedBlock = ({
        name
      }) => name === (0, _blocks.getUnregisteredTypeHandlerName)();
      const unsupportedBlockNames = blocks.filter(isUnsupportedBlock).map(block => block.attributes.originalName);
      _reactNativeBridge.default.editorDidMount(unsupportedBlockNames);
    }
  }
  onHardwareBackPress() {
    const {
      clearSelectedBlock,
      selectedBlockIndex
    } = this.props;
    if (selectedBlockIndex !== -1) {
      clearSelectedBlock();
      return true;
    }
    return false;
  }
  onContentUpdate({
    content: rawContent
  }) {
    const {
      editTitle,
      onClearPostTitleSelection,
      onInsertBlockAfter: onInsertBlocks,
      title
    } = this.props;
    const content = (0, _blocks.pasteHandler)({
      plainText: rawContent
    });
    (0, _postTitle.insertContentWithTitle)(title, content, editTitle, onInsertBlocks);
    onClearPostTitleSelection();
  }
  serializeToNativeAction() {
    const title = this.props.title;
    let html;
    if (this.props.mode === 'text') {
      // The HTMLTextInput component does not update the store when user is doing changes
      // Let's request the HTML from the component's state directly.
      html = (0, _hooks.applyFilters)('native.persist-html');
    } else {
      html = (0, _blocks.serialize)(this.props.blocks);
    }
    const hasChanges = title !== this.post.title.raw || html !== this.post.content.raw;

    // Variable to store the content structure metrics.
    const contentInfo = {};
    contentInfo.characterCount = (0, _wordcount.count)(html, 'characters_including_spaces');
    contentInfo.wordCount = (0, _wordcount.count)(html, 'words');
    contentInfo.paragraphCount = this.props.paragraphCount;
    contentInfo.blockCount = this.props.blockCount;
    _reactNativeBridge.default.provideToNative_Html(html, title, hasChanges, contentInfo);
    if (hasChanges) {
      this.post.title.raw = title;
      this.post.content.raw = html;
    }
  }
  updateHtmlAction(html) {
    const parsed = (0, _blocks.parse)(html);
    this.props.resetEditorBlocksWithoutUndoLevel(parsed);
  }
  replaceBlockAction(html, blockClientId) {
    const parsed = (0, _blocks.parse)(html);
    this.props.replaceBlock(blockClientId, parsed);
  }
  toggleMode() {
    const {
      mode,
      switchMode
    } = this.props;
    // Refresh html content first.
    this.serializeToNativeAction();
    switchMode(mode === 'visual' ? 'text' : 'visual');
  }
  updateCapabilitiesAction(capabilities) {
    this.props.updateEditorSettings({
      capabilities
    });
  }
  render() {
    const {
      children,
      post,
      capabilities,
      settings,
      ...props
    } = this.props;
    const editorSettings = this.getEditorSettings(settings, capabilities);
    return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index.default, {
        post: this.post,
        settings: editorSettings,
        ...props,
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSafeAreaContext.SafeAreaProvider, {
          children: children
        })
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_editor.EditorHelpTopics, {
        isVisible: this.state.isHelpVisible,
        onClose: () => this.setState({
          isHelpVisible: false
        }),
        close: () => this.setState({
          isHelpVisible: false
        }),
        showSupport: capabilities?.supportSection === true
      })]
    });
  }
}
const ComposedNativeProvider = exports.ExperimentalEditorProvider = (0, _compose.compose)([(0, _data.withSelect)(select => {
  var _settings$colors, _settings$gradients;
  const {
    __unstableIsEditorReady: isEditorReady,
    getEditorBlocks,
    getEditedPostAttribute,
    getEditedPostContent,
    getEditorSettings,
    getEditorMode
  } = select(_editor.store);
  const {
    getBlockIndex,
    getSelectedBlockClientId,
    getGlobalBlockCount
  } = select(_blockEditor.store);
  const settings = getEditorSettings();
  const defaultEditorColors = (_settings$colors = settings?.colors) !== null && _settings$colors !== void 0 ? _settings$colors : [];
  const defaultEditorGradients = (_settings$gradients = settings?.gradients) !== null && _settings$gradients !== void 0 ? _settings$gradients : [];
  const selectedBlockClientId = getSelectedBlockClientId();
  return {
    mode: getEditorMode(),
    isReady: isEditorReady(),
    blocks: getEditorBlocks(),
    title: getEditedPostAttribute('title'),
    getEditedPostContent,
    defaultEditorColors,
    defaultEditorGradients,
    selectedBlockIndex: getBlockIndex(selectedBlockClientId),
    blockCount: getGlobalBlockCount(),
    paragraphCount: getGlobalBlockCount('core/paragraph')
  };
}), (0, _data.withDispatch)(dispatch => {
  const {
    editPost,
    resetEditorBlocks,
    updateEditorSettings,
    switchEditorMode,
    togglePostTitleSelection
  } = dispatch(_editor.store);
  const {
    clearSelectedBlock,
    updateSettings,
    insertBlock,
    insertBlocks,
    replaceBlock
  } = dispatch(_blockEditor.store);
  const {
    addEntities,
    receiveEntityRecords
  } = dispatch(_coreData.store);
  const {
    createSuccessNotice,
    createErrorNotice
  } = dispatch(_notices.store);
  return {
    updateBlockEditorSettings: updateSettings,
    updateEditorSettings,
    addEntities,
    insertBlock,
    insertBlocks,
    createSuccessNotice,
    createErrorNotice,
    clearSelectedBlock,
    editTitle(title) {
      editPost({
        title
      });
    },
    receiveEntityRecords,
    resetEditorBlocksWithoutUndoLevel(blocks) {
      resetEditorBlocks(blocks, {
        __unstableShouldCreateUndoLevel: false
      });
    },
    switchMode(mode) {
      switchEditorMode(mode);
    },
    onInsertBlockAfter(blocks) {
      insertBlocks(blocks, undefined, undefined, false);
    },
    onClearPostTitleSelection() {
      togglePostTitleSelection(false);
    },
    replaceBlock
  };
})])(NativeEditorProvider);
var _default = exports.default = ComposedNativeProvider;
//# sourceMappingURL=index.native.js.map