"use strict";

exports.__esModule = true;
require("core-js/modules/es.array.push.js");
require("core-js/modules/es.error.cause.js");
var _base = require("../base");
var _pluginHooks = _interopRequireDefault(require("../../pluginHooks"));
var _SheetClip = require("../../3rdparty/SheetClip");
var _string = require("../../helpers/string");
var _element = require("../../helpers/dom/element");
var _browser = require("../../helpers/browser");
var _copy = _interopRequireDefault(require("./contextMenuItem/copy"));
var _copyColumnHeadersOnly = _interopRequireDefault(require("./contextMenuItem/copyColumnHeadersOnly"));
var _copyWithColumnGroupHeaders = _interopRequireDefault(require("./contextMenuItem/copyWithColumnGroupHeaders"));
var _copyWithColumnHeaders = _interopRequireDefault(require("./contextMenuItem/copyWithColumnHeaders"));
var _cut = _interopRequireDefault(require("./contextMenuItem/cut"));
var _copyableRanges = require("./copyableRanges");
var _parseTable = require("../../utils/parseTable");
var _eventManager = _interopRequireDefault(require("../../eventManager"));
var _clipboardData = require("./clipboardData");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
_pluginHooks.default.getSingleton().register('afterCopyLimit');
_pluginHooks.default.getSingleton().register('modifyCopyableRange');
_pluginHooks.default.getSingleton().register('beforeCut');
_pluginHooks.default.getSingleton().register('afterCut');
_pluginHooks.default.getSingleton().register('beforePaste');
_pluginHooks.default.getSingleton().register('afterPaste');
_pluginHooks.default.getSingleton().register('beforeCopy');
_pluginHooks.default.getSingleton().register('afterCopy');
const PLUGIN_KEY = exports.PLUGIN_KEY = 'copyPaste';
const PLUGIN_PRIORITY = exports.PLUGIN_PRIORITY = 80;
const SETTING_KEYS = ['fragmentSelection'];

/* eslint-disable jsdoc/require-description-complete-sentence */
/**
 * @description
 * Copy, cut, and paste data by using the `CopyPaste` plugin.
 *
 * Control the `CopyPaste` plugin programmatically through its [API methods](#methods).
 *
 * The user can access the copy-paste features through:
 * - The [context menu](@/guides/cell-features/clipboard.md#context-menu).
 * - The [keyboard shortcuts](@/guides/cell-features/clipboard.md#related-keyboard-shortcuts).
 * - The browser's menu bar.
 *
 * Read more:
 * - [Guides: Clipboard](@/guides/cell-features/clipboard.md)
 * - [Configuration options: `copyPaste`](@/api/options.md#copypaste)
 *
 * @example
 * ```js
 * // enable the plugin with the default configuration
 * copyPaste: true,
 *
 * // or, enable the plugin with a custom configuration
 * copyPaste: {
 *   columnsLimit: 25,
 *   rowsLimit: 50,
 *   pasteMode: 'shift_down',
 *   copyColumnHeaders: true,
 *   copyColumnGroupHeaders: true,
 *   copyColumnHeadersOnly: true,
 *   uiContainer: document.body,
 * },
 * ```
 * @class CopyPaste
 * @plugin CopyPaste
 */
var _enableCopyColumnHeaders = /*#__PURE__*/new WeakMap();
var _enableCopyColumnGroupHeaders = /*#__PURE__*/new WeakMap();
var _enableCopyColumnHeadersOnly = /*#__PURE__*/new WeakMap();
var _copyMode = /*#__PURE__*/new WeakMap();
var _isTriggeredByCopy = /*#__PURE__*/new WeakMap();
var _isTriggeredByCut = /*#__PURE__*/new WeakMap();
var _copyableRangesFactory = /*#__PURE__*/new WeakMap();
var _ensureClipboardEventsGetTriggered = /*#__PURE__*/new WeakSet();
var _addContentEditableToHighlightedCell = /*#__PURE__*/new WeakSet();
var _removeContentEditableFromHighlightedCell = /*#__PURE__*/new WeakSet();
class CopyPaste extends _base.BasePlugin {
  constructor() {
    super(...arguments);
    /**
     * Remove the `contenteditable` attribute from the highlighted cell and deselect its content.
     */
    _classPrivateMethodInitSpec(this, _removeContentEditableFromHighlightedCell);
    /**
     * Add the `contenteditable` attribute to the highlighted cell and select its content.
     */
    _classPrivateMethodInitSpec(this, _addContentEditableToHighlightedCell);
    /**
     * Ensure that the `copy`/`cut` events get triggered properly in Safari.
     *
     * @param {string} eventName Name of the event to get triggered.
     */
    _classPrivateMethodInitSpec(this, _ensureClipboardEventsGetTriggered);
    /**
     * The maximum number of columns than can be copied to the clipboard.
     *
     * @type {number}
     * @default Infinity
     */
    _defineProperty(this, "columnsLimit", Infinity);
    /**
     * The maximum number of rows than can be copied to the clipboard.
     *
     * @type {number}
     * @default Infinity
     */
    _defineProperty(this, "rowsLimit", Infinity);
    /**
     * When pasting:
     * - `'overwrite'`: overwrite the currently-selected cells
     * - `'shift_down'`: move currently-selected cells down
     * - `'shift_right'`: move currently-selected cells to the right
     *
     * @type {string}
     * @default 'overwrite'
     */
    _defineProperty(this, "pasteMode", 'overwrite');
    /**
     * The UI container for the secondary focusable element.
     *
     * @type {HTMLElement}
     */
    _defineProperty(this, "uiContainer", this.hot.rootDocument.body);
    /**
     * Shows the "Copy with headers" item in the context menu and extends the context menu with the
     * `'copy_with_column_headers'` option that can be used for creating custom menus arrangements.
     *
     * @type {boolean}
     * @default false
     */
    _classPrivateFieldInitSpec(this, _enableCopyColumnHeaders, {
      writable: true,
      value: false
    });
    /**
     * Shows the "Copy with group headers" item in the context menu and extends the context menu with the
     * `'copy_with_column_group headers'` option that can be used for creating custom menus arrangements.
     *
     * @type {boolean}
     * @default false
     */
    _classPrivateFieldInitSpec(this, _enableCopyColumnGroupHeaders, {
      writable: true,
      value: false
    });
    /**
     * Shows the "Copy headers only" item in the context menu and extends the context menu with the
     * `'copy_column_headers_only'` option that can be used for creating custom menus arrangements.
     *
     * @type {boolean}
     * @default false
     */
    _classPrivateFieldInitSpec(this, _enableCopyColumnHeadersOnly, {
      writable: true,
      value: false
    });
    /**
     * Defines the data range to copy. Possible values:
     *  * `'cells-only'` Copy selected cells only;
     *  * `'column-headers-only'` Copy column headers only;
     *  * `'with-column-group-headers'` Copy cells with all column headers;
     *  * `'with-column-headers'` Copy cells with column headers;
     *
     * @type {'cells-only' | 'column-headers-only' | 'with-column-group-headers' | 'with-column-headers'}
     */
    _classPrivateFieldInitSpec(this, _copyMode, {
      writable: true,
      value: 'cells-only'
    });
    /**
     * Flag that is used to prevent copying when the native shortcut was not pressed.
     *
     * @type {boolean}
     */
    _classPrivateFieldInitSpec(this, _isTriggeredByCopy, {
      writable: true,
      value: false
    });
    /**
     * Flag that is used to prevent cutting when the native shortcut was not pressed.
     *
     * @type {boolean}
     */
    _classPrivateFieldInitSpec(this, _isTriggeredByCut, {
      writable: true,
      value: false
    });
    /**
     * Class that helps generate copyable ranges based on the current selection for different copy mode
     * types.
     *
     * @type {CopyableRangesFactory}
     */
    _classPrivateFieldInitSpec(this, _copyableRangesFactory, {
      writable: true,
      value: new _copyableRanges.CopyableRangesFactory({
        countRows: () => this.hot.countRows(),
        countColumns: () => this.hot.countCols(),
        rowsLimit: () => this.rowsLimit,
        columnsLimit: () => this.columnsLimit,
        countColumnHeaders: () => this.hot.view.getColumnHeadersCount()
      })
    });
    /**
     * Ranges of the cells coordinates, which should be used to copy/cut/paste actions.
     *
     * @private
     * @type {Array<{startRow: number, startCol: number, endRow: number, endCol: number}>}
     */
    _defineProperty(this, "copyableRanges", []);
  }
  static get PLUGIN_KEY() {
    return PLUGIN_KEY;
  }
  static get SETTING_KEYS() {
    return [PLUGIN_KEY, ...SETTING_KEYS];
  }
  static get PLUGIN_PRIORITY() {
    return PLUGIN_PRIORITY;
  }
  /**
   * Checks if the [`CopyPaste`](#copypaste) plugin is enabled.
   *
   * This method gets called by Handsontable's [`beforeInit`](@/api/hooks.md#beforeinit) hook.
   * If it returns `true`, the [`enablePlugin()`](#enableplugin) method gets called.
   *
   * @returns {boolean}
   */
  isEnabled() {
    return !!this.hot.getSettings()[PLUGIN_KEY];
  }

  /**
   * Enables the [`CopyPaste`](#copypaste) plugin for your Handsontable instance.
   */
  enablePlugin() {
    var _this = this;
    if (this.enabled) {
      return;
    }
    const {
      [PLUGIN_KEY]: settings
    } = this.hot.getSettings();
    if (typeof settings === 'object') {
      var _settings$pasteMode, _settings$uiContainer;
      this.pasteMode = (_settings$pasteMode = settings.pasteMode) !== null && _settings$pasteMode !== void 0 ? _settings$pasteMode : this.pasteMode;
      this.rowsLimit = isNaN(settings.rowsLimit) ? this.rowsLimit : settings.rowsLimit;
      this.columnsLimit = isNaN(settings.columnsLimit) ? this.columnsLimit : settings.columnsLimit;
      _classPrivateFieldSet(this, _enableCopyColumnHeaders, !!settings.copyColumnHeaders);
      _classPrivateFieldSet(this, _enableCopyColumnGroupHeaders, !!settings.copyColumnGroupHeaders);
      _classPrivateFieldSet(this, _enableCopyColumnHeadersOnly, !!settings.copyColumnHeadersOnly);
      this.uiContainer = (_settings$uiContainer = settings.uiContainer) !== null && _settings$uiContainer !== void 0 ? _settings$uiContainer : this.uiContainer;
    }
    this.addHook('afterContextMenuDefaultOptions', options => this.onAfterContextMenuDefaultOptions(options));
    this.addHook('afterSelectionEnd', () => this.onAfterSelectionEnd());
    this.eventManager = new _eventManager.default(this);
    this.eventManager.addEventListener(this.hot.rootDocument, 'copy', function () {
      return _this.onCopy(...arguments);
    });
    this.eventManager.addEventListener(this.hot.rootDocument, 'cut', function () {
      return _this.onCut(...arguments);
    });
    this.eventManager.addEventListener(this.hot.rootDocument, 'paste', function () {
      return _this.onPaste(...arguments);
    });

    // Without this workaround Safari (tested on Safari@16.5.2) does allow copying/cutting from the browser menu.
    if ((0, _browser.isSafari)()) {
      this.eventManager.addEventListener(this.hot.rootDocument.body, 'mouseenter', function () {
        return _this.onSafariMouseEnter(...arguments);
      });
      this.eventManager.addEventListener(this.hot.rootDocument.body, 'mouseleave', function () {
        return _this.onSafariMouseLeave(...arguments);
      });
      this.addHook('afterSelection', () => this.onSafariAfterSelection());
    }
    super.enablePlugin();
  }

  /**
   * Updates the state of the [`CopyPaste`](#copypaste) plugin.
   *
   * Gets called when [`updateSettings()`](@/api/core.md#updatesettings)
   * is invoked with any of the following configuration options:
   *  - [`copyPaste`](@/api/options.md#copypaste)
   *  - [`fragmentSelection`](@/api/options.md#fragmentselection)
   */
  updatePlugin() {
    this.disablePlugin();
    this.enablePlugin();
    super.updatePlugin();
  }

  /**
   * Disables the [`CopyPaste`](#copypaste) plugin for your Handsontable instance.
   */
  disablePlugin() {
    super.disablePlugin();
  }

  /**
   * Copies the contents of the selected cells (and/or their related column headers) to the system clipboard.
   *
   * Takes an optional parameter (`copyMode`) that defines the scope of copying:
   *
   * | `copyMode` value              | Description                                                     |
   * | ----------------------------- | --------------------------------------------------------------- |
   * | `'cells-only'` (default)      | Copy the selected cells                                         |
   * | `'with-column-headers'`       | - Copy the selected cells<br>- Copy the nearest column headers  |
   * | `'with-column-group-headers'` | - Copy the selected cells<br>- Copy all related columns headers |
   * | `'column-headers-only'`       | Copy the nearest column headers (without copying cells)         |
   *
   * @param {string} [copyMode='cells-only'] Copy mode.
   */
  copy() {
    let copyMode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'cells-only';
    _classPrivateFieldSet(this, _copyMode, copyMode);
    _classPrivateFieldSet(this, _isTriggeredByCopy, true);
    _classPrivateMethodGet(this, _ensureClipboardEventsGetTriggered, _ensureClipboardEventsGetTriggered2).call(this, 'copy');
  }

  /**
   * Copies the contents of the selected cells.
   */
  copyCellsOnly() {
    this.copy('cells-only');
  }
  /**
   * Copies the contents of column headers that are nearest to the selected cells.
   */
  copyColumnHeadersOnly() {
    this.copy('column-headers-only');
  }
  /**
   * Copies the contents of the selected cells and all their related column headers.
   */
  copyWithAllColumnHeaders() {
    this.copy('with-column-group-headers');
  }
  /**
   * Copies the contents of the selected cells and their nearest column headers.
   */
  copyWithColumnHeaders() {
    this.copy('with-column-headers');
  }

  /**
   * Cuts the contents of the selected cells to the system clipboard.
   */
  cut() {
    _classPrivateFieldSet(this, _isTriggeredByCut, true);
    _classPrivateMethodGet(this, _ensureClipboardEventsGetTriggered, _ensureClipboardEventsGetTriggered2).call(this, 'cut');
  }

  /**
   * Converts the contents of multiple ranges (`ranges`) into a single string.
   *
   * @param {Array<{startRow: number, startCol: number, endRow: number, endCol: number}>} ranges Array of objects with properties `startRow`, `endRow`, `startCol` and `endCol`.
   * @returns {string} A string that will be copied to the clipboard.
   */
  getRangedCopyableData(ranges) {
    return (0, _SheetClip.stringify)(this.getRangedData(ranges));
  }

  /**
   * Converts the contents of multiple ranges (`ranges`) into an array of arrays.
   *
   * @param {Array<{startRow: number, startCol: number, endRow: number, endCol: number}>} ranges Array of objects with properties `startRow`, `startCol`, `endRow` and `endCol`.
   * @returns {Array[]} An array of arrays that will be copied to the clipboard.
   */
  getRangedData(ranges) {
    const {
      rows,
      columns
    } = (0, _copyableRanges.normalizeRanges)(ranges);
    return (0, _parseTable.getDataByCoords)(this.hot, {
      rows,
      columns
    });
  }

  /**
   * Simulates the paste action.
   *
   * For security reasons, modern browsers don't allow reading from the system clipboard.
   *
   * @param {string} pastableText The value to paste, as a raw string.
   * @param {string} [pastableHtml=''] The value to paste, as HTML.
   */
  paste() {
    let pastableText = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    let pastableHtml = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : pastableText;
    if (!pastableText && !pastableHtml) {
      return;
    }
    const pasteData = {
      clipboardData: {
        data: {},
        setData(type, value) {
          this.data[type] = value;
        },
        getData(type) {
          return this.data[type];
        }
      }
    };
    if (pastableText) {
      pasteData.clipboardData.setData('text/plain', pastableText);
    }
    if (pastableHtml) {
      pasteData.clipboardData.setData('text/html', pastableHtml);
    }
    this.onPaste(pasteData);
  }

  /**
   * Prepares copyable text from the cells selection in the invisible textarea.
   */
  setCopyableText() {
    const selectionRange = this.hot.getSelectedRangeLast();
    if (!selectionRange) {
      return;
    }
    if (selectionRange.isSingleHeader()) {
      this.copyableRanges = [];
      return;
    }
    _classPrivateFieldGet(this, _copyableRangesFactory).setSelectedRange(selectionRange);
    const groupedRanges = new Map([['headers', null], ['cells', null]]);
    if (_classPrivateFieldGet(this, _copyMode) === 'column-headers-only') {
      groupedRanges.set('headers', _classPrivateFieldGet(this, _copyableRangesFactory).getMostBottomColumnHeadersRange());
    } else {
      if (_classPrivateFieldGet(this, _copyMode) === 'with-column-headers') {
        groupedRanges.set('headers', _classPrivateFieldGet(this, _copyableRangesFactory).getMostBottomColumnHeadersRange());
      } else if (_classPrivateFieldGet(this, _copyMode) === 'with-column-group-headers') {
        groupedRanges.set('headers', _classPrivateFieldGet(this, _copyableRangesFactory).getAllColumnHeadersRange());
      }
      groupedRanges.set('cells', _classPrivateFieldGet(this, _copyableRangesFactory).getCellsRange());
    }
    this.copyableRanges = Array.from(groupedRanges.values()).filter(range => range !== null).map(_ref => {
      let {
        startRow,
        startCol,
        endRow,
        endCol
      } = _ref;
      return {
        startRow,
        startCol,
        endRow,
        endCol
      };
    });
    this.copyableRanges = this.hot.runHooks('modifyCopyableRange', this.copyableRanges);
    const cellsRange = groupedRanges.get('cells');
    if (cellsRange !== null && cellsRange.isRangeTrimmed) {
      const {
        startRow,
        startCol,
        endRow,
        endCol
      } = cellsRange;
      this.hot.runHooks('afterCopyLimit', endRow - startRow + 1, endCol - startCol + 1, this.rowsLimit, this.columnsLimit);
    }
  }

  /**
   * Verifies if editor exists and is open.
   *
   * @private
   * @returns {boolean}
   */
  isEditorOpened() {
    var _this$hot$getActiveEd;
    return (_this$hot$getActiveEd = this.hot.getActiveEditor()) === null || _this$hot$getActiveEd === void 0 ? void 0 : _this$hot$getActiveEd.isOpened();
  }
  /**
   * Prepares new values to populate them into datasource.
   *
   * @private
   * @param {Array} inputArray An array of the data to populate.
   * @param {Array} [selection] The selection which indicates from what position the data will be populated.
   * @returns {Array} Range coordinates after populate data.
   */
  populateValues(inputArray) {
    let selection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.hot.getSelectedRangeLast();
    if (!inputArray.length) {
      return;
    }
    const populatedRowsLength = inputArray.length;
    const populatedColumnsLength = inputArray[0].length;
    const newRows = [];
    const {
      row: startRow,
      col: startColumn
    } = selection.getTopStartCorner();
    const {
      row: endRowFromSelection,
      col: endColumnFromSelection
    } = selection.getBottomEndCorner();
    let visualRowForPopulatedData = startRow;
    let visualColumnForPopulatedData = startColumn;
    let lastVisualRow = startRow;
    let lastVisualColumn = startColumn;

    // We try to populate just all copied data or repeat copied data within a selection. Please keep in mind that we
    // don't know whether populated data is bigger than selection on start as there are some cells for which values
    // should be not inserted (it's known right after getting cell meta).
    while (newRows.length < populatedRowsLength || visualRowForPopulatedData <= endRowFromSelection) {
      const {
        skipRowOnPaste,
        visualRow
      } = this.hot.getCellMeta(visualRowForPopulatedData, startColumn);
      visualRowForPopulatedData = visualRow + 1;
      if (skipRowOnPaste === true) {
        /* eslint-disable no-continue */
        continue;
      }
      lastVisualRow = visualRow;
      visualColumnForPopulatedData = startColumn;
      const newRow = [];
      const insertedRow = newRows.length % populatedRowsLength;
      while (newRow.length < populatedColumnsLength || visualColumnForPopulatedData <= endColumnFromSelection) {
        const {
          skipColumnOnPaste,
          visualCol
        } = this.hot.getCellMeta(startRow, visualColumnForPopulatedData);
        visualColumnForPopulatedData = visualCol + 1;
        if (skipColumnOnPaste === true) {
          /* eslint-disable no-continue */
          continue;
        }
        lastVisualColumn = visualCol;
        const insertedColumn = newRow.length % populatedColumnsLength;
        newRow.push(inputArray[insertedRow][insertedColumn]);
      }
      newRows.push(newRow);
    }
    this.hot.populateFromArray(startRow, startColumn, newRows, void 0, void 0, 'CopyPaste.paste', this.pasteMode);
    return [startRow, startColumn, lastVisualRow, lastVisualColumn];
  }
  /**
   * `copy` event callback on textarea element.
   *
   * @param {ClipboardEvent} event ClipboardEvent.
   * @private
   */
  onCopy(event) {
    if (!this.hot.isListening() && !_classPrivateFieldGet(this, _isTriggeredByCopy) || this.isEditorOpened()) {
      return;
    }
    this.setCopyableText();
    _classPrivateFieldSet(this, _isTriggeredByCopy, false);
    const copyClipboardData = new _clipboardData.CopyClipboardData(this.hot, this.copyableRanges);
    const allowCopying = !!this.hot.runHooks('beforeCopy', copyClipboardData);
    if (allowCopying) {
      event.clipboardData.setData('text/plain', (0, _SheetClip.stringify)(copyClipboardData.getData()));
      event.clipboardData.setData('text/html', [copyClipboardData.getType() === 'handsontable' ? _clipboardData.META_HEAD : '', (0, _parseTable.getHTMLFromConfig)(copyClipboardData.getMetaInfo())].join(''));
      this.hot.runHooks('afterCopy', copyClipboardData);
    }
    _classPrivateFieldSet(this, _copyMode, 'cells-only');
    event.preventDefault();
  }

  /**
   * `cut` event callback on textarea element.
   *
   * @param {ClipboardEvent} event ClipboardEvent.
   * @private
   */
  onCut(event) {
    if (!this.hot.isListening() && !_classPrivateFieldGet(this, _isTriggeredByCut) || this.isEditorOpened()) {
      return;
    }
    this.setCopyableText();
    _classPrivateFieldSet(this, _isTriggeredByCut, false);
    const copyClipboardData = new _clipboardData.CopyClipboardData(this.hot, this.copyableRanges);
    const allowCuttingOut = !!this.hot.runHooks('beforeCut', copyClipboardData);
    if (allowCuttingOut) {
      event.clipboardData.setData('text/plain', (0, _SheetClip.stringify)(copyClipboardData.getData()));
      event.clipboardData.setData('text/html', [copyClipboardData.getType() === 'handsontable' ? _clipboardData.META_HEAD : '', (0, _parseTable.getHTMLFromConfig)(copyClipboardData.getMetaInfo())].join(''));
      this.hot.emptySelectedCells('CopyPaste.cut');
      this.hot.runHooks('afterCut', copyClipboardData);
    }
    event.preventDefault();
  }

  /**
   * `paste` event callback on textarea element.
   *
   * @param {Event} event ClipboardEvent or pseudo ClipboardEvent, if paste was called manually.
   * @private
   */
  onPaste(event) {
    if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected()) {
      return;
    }
    if (event && event.preventDefault) {
      event.preventDefault();
    }
    const html = (0, _string.sanitize)(event.clipboardData.getData('text/html'), {
      ADD_TAGS: ['meta'],
      ADD_ATTR: ['content'],
      FORCE_BODY: true
    });
    const pasteClipboardData = new _clipboardData.PasteClipboardData(event.clipboardData.getData('text/plain'), html);
    if (this.hot.runHooks('beforePaste', pasteClipboardData) === false) {
      return;
    }
    const pastedTable = pasteClipboardData.getData();
    if (pastedTable.length === 0) {
      return;
    }
    const [startRow, startColumn, endRow, endColumn] = this.populateValues(pastedTable);
    this.hot.selectCell(startRow, startColumn, Math.min(this.hot.countRows() - 1, endRow), Math.min(this.hot.countCols() - 1, endColumn));
    this.hot.runHooks('afterPaste', pasteClipboardData);
  }

  /**
   * Add copy and cut options to the Context Menu.
   *
   * @private
   * @param {object} options Contains default added options of the Context Menu.
   */
  onAfterContextMenuDefaultOptions(options) {
    options.items.push({
      name: '---------'
    }, (0, _copy.default)(this));
    if (_classPrivateFieldGet(this, _enableCopyColumnHeaders)) {
      options.items.push((0, _copyWithColumnHeaders.default)(this));
    }
    if (_classPrivateFieldGet(this, _enableCopyColumnGroupHeaders)) {
      options.items.push((0, _copyWithColumnGroupHeaders.default)(this));
    }
    if (_classPrivateFieldGet(this, _enableCopyColumnHeadersOnly)) {
      options.items.push((0, _copyColumnHeadersOnly.default)(this));
    }
    options.items.push((0, _cut.default)(this));
  }

  /**
   * Force focus on focusableElement after end of the selection.
   *
   * @private
   */
  onAfterSelectionEnd() {
    if (this.isEditorOpened()) {
      return;
    }
    if (this.hot.getSettings().fragmentSelection) {
      return;
    }
    this.setCopyableText();
  }

  /**
   * `document.body` `mouseenter` callback used to work around a Safari's problem with copying/cutting from the
   * browser's menu.
   *
   * @private
   */
  onSafariMouseEnter() {
    _classPrivateMethodGet(this, _removeContentEditableFromHighlightedCell, _removeContentEditableFromHighlightedCell2).call(this);
  }

  /**
   * `document.body` `mouseleave` callback used to work around a Safari's problem with copying/cutting from the
   * browser's menu.
   *
   * @private
   */
  onSafariMouseLeave() {
    _classPrivateMethodGet(this, _addContentEditableToHighlightedCell, _addContentEditableToHighlightedCell2).call(this);
  }

  /**
   * `afterSelection` hook callback triggered only on Safari.
   *
   * @private
   */
  onSafariAfterSelection() {
    _classPrivateMethodGet(this, _removeContentEditableFromHighlightedCell, _removeContentEditableFromHighlightedCell2).call(this);
  }

  /**
   * Destroys the `CopyPaste` plugin instance.
   */
  destroy() {
    super.destroy();
  }
}
exports.CopyPaste = CopyPaste;
function _ensureClipboardEventsGetTriggered2(eventName) {
  // Without this workaround Safari (tested on Safari@16.5.2) does not trigger the 'copy' event.
  if ((0, _browser.isSafari)()) {
    const lastSelectedRange = this.hot.getSelectedRangeLast();
    if (lastSelectedRange) {
      const {
        row: highlightRow,
        col: highlightColumn
      } = lastSelectedRange.highlight;
      const currentlySelectedCell = this.hot.getCell(highlightRow, highlightColumn, true);
      if (currentlySelectedCell) {
        (0, _element.runWithSelectedContendEditableElement)(currentlySelectedCell, () => {
          this.hot.rootDocument.execCommand(eventName);
        });
      }
    }
  } else {
    this.hot.rootDocument.execCommand(eventName);
  }
}
function _addContentEditableToHighlightedCell2() {
  if (this.hot.isListening()) {
    const lastSelectedRange = this.hot.getSelectedRangeLast();
    if (lastSelectedRange) {
      const {
        row: highlightRow,
        col: highlightColumn
      } = lastSelectedRange.highlight;
      const currentlySelectedCell = this.hot.getCell(highlightRow, highlightColumn, true);
      if (currentlySelectedCell) {
        (0, _element.makeElementContentEditableAndSelectItsContent)(currentlySelectedCell);
      }
    }
  }
}
function _removeContentEditableFromHighlightedCell2() {
  // If the instance is not listening, the workaround is not needed.
  if (this.hot.isListening()) {
    const lastSelectedRange = this.hot.getSelectedRangeLast();
    if (lastSelectedRange) {
      const {
        row: highlightRow,
        col: highlightColumn
      } = lastSelectedRange.highlight;
      const currentlySelectedCell = this.hot.getCell(highlightRow, highlightColumn, true);
      if (currentlySelectedCell !== null && currentlySelectedCell !== void 0 && currentlySelectedCell.hasAttribute('contenteditable')) {
        (0, _element.removeContentEditableFromElementAndDeselect)(currentlySelectedCell);
      }
    }
  }
}