<commit_before>import BasePlugin from './../_base';
import {offset, outerHeight, outerWidth} from './../../helpers/dom/element';
import {eventManager as eventManagerObject} from './../../eventManager';
import {registerPlugin} from './../../plugins';
import {WalkontableCellCoords} from './../../3rdparty/walkontable/src/cell/coords';
import {getDeltas, settingsFactory, getDirectionAndRange} from './utils';
import {isObject} from './../../helpers/object';

const privatePool = new WeakMap();

/**
 * This plugin provides "drag-down" and "copy-down" functionalities, both operated
 * using the small square in the right bottom of the cell selection.
 *
 * "Drag-down" expands the value of the selected cells to the neighbouring
 * cells when you drag the small square in the corner.
 *
 * "Copy-down" copies the value of the selection to all empty cells
 * below when you double click the small square.
 *
 * @class Autofill
 * @plugin Autofill
 */

class Autofill extends BasePlugin {
  constructor(hotInstance) {
    super(hotInstance);

    this.eventManager = eventManagerObject(this);
    this.addingStarted = false;
    this.mouseDownOnCellCorner = false;
    this.mouseDragOutside = false;
    this.handle = {
      isDragged: 0,
      disabled: false
    };

    privatePool.set(this, {
      settings: settingsFactory(this.hot.getSettings().fillHandle)
    });
  }

  /**
   * Bind the events used by the plugin.
   *
   * @private
   */
  registerEvents() {
    this.eventManager.addEventListener(document, 'mouseup', () => this.onMouseUp());
    this.eventManager.addEventListener(document, 'mousemove', (event) => this.onMouseMove(event));
  }

  /**
   * Check if the plugin is enabled in the Handsontable settings.
   *
   * @returns {Boolean}
   */
  isEnabled() {
    return this.hot.getSettings().fillHandle === true || this.hot.getSettings().fillHandle === 'horizontal' ||
      this.hot.getSettings().fillHandle === 'vertical' || isObject(this.hot.getSettings().fillHandle);
  }

  /**
   * Enable plugin for this Handsontable instance.
   */
  enablePlugin() {
    if (this.enabled) {
      return;
    }

    this.registerEvents();

    this.addHook('afterOnCellCornerMouseDown', (event) => this.onAfterCellCornerMouseDown(event));
    this.addHook('beforeOnCellMouseOver', (event, coords, TD) => this.onBeforeCellMouseOver(coords));
    this.addHook('init', () => {
      this.hot.view.wt.wtSettings.settings.onCellCornerDblClick = () => {
        this.selectAdjacent();
      };
    });

    super.enablePlugin();
  }

  /**
   * Disable plugin for this Handsontable instance.
   */
  disablePlugin() {
    super.disablePlugin();
  }

  /**
   * Selects cells down to the last row in the left column, then fills down to that cell
   *
   * @function selectAdjacent
   * @memberof Autofill#
   */
  selectAdjacent() {
    let select;
    const data = this.hot.getData();
    var r, maxR, c;

    if (this.hot.selection.isMultiple()) {
      select = this.hot.view.wt.selections.area.getCorners();

    } else {
      select = this.hot.view.wt.selections.current.getCorners();
    }

    rows: for (r = select[2] + 1; r < this.hot.countRows(); r++) {
      for (c = select[1]; c <= select[3]; c++) {
        if (data[r][c]) {
          break rows;
        }
      }
      if (!!data[r][select[1] - 1] || !!data[r][select[3] + 1]) {
        maxR = r;
      }
    }
    if (maxR) {
      this.hot.view.wt.selections.fill.clear();
      this.hot.view.wt.selections.fill.add(new WalkontableCellCoords(select[0], select[1]));
      this.hot.view.wt.selections.fill.add(new WalkontableCellCoords(maxR, select[3]));
      this.apply();
    }
  }

  /**
   * Apply fill values to the area in fill border, omitting the selection border
   *
   * @function apply
   * @memberof Autofill#
   */
  apply() {
    if (this.hot.view.wt.selections.fill.isEmpty()) {
      return;
    }

    const selectionsFillCorners = this.hot.view.wt.selections.fill.getCorners();
    let select;

    this.handle.isDragged = 0;
    this.hot.view.wt.selections.fill.clear();

    if (this.hot.selection.isMultiple()) {
      select = this.hot.view.wt.selections.area.getCorners();
    } else {
      select = this.hot.view.wt.selections.current.getCorners();
    }

    const {direction, start, end} = getDirectionAndRange(select, selectionsFillCorners);

    this.hot.runHooks('afterAutofillApplyValues', select, selectionsFillCorners);

    if (start && start.row > -1 && start.col > -1) {
      const selRange = {
        from: this.hot.getSelectedRange().from,
        to: this.hot.getSelectedRange().to,
      };

      const data = this.hot.getData(selRange.from.row, selRange.from.col, selRange.to.row, selRange.to.col);
      const deltas = getDeltas(start, end, data, direction);

      this.hot.runHooks('beforeAutofill', start, end, data);
      this.hot.populateFromArray(start.row, start.col, data, end.row, end.col, 'autofill', null, direction, deltas);

      this.hot.selection.setRangeStart(new WalkontableCellCoords(selectionsFillCorners[0], selectionsFillCorners[1]));
      this.hot.selection.setRangeEnd(new WalkontableCellCoords(selectionsFillCorners[2], selectionsFillCorners[3]));

    } else {
      // reset to avoid some range bug
      this.hot.selection.refreshBorders();
    }
  }

  /**
   * Show fill border
   *
   * @function showBorder
   * @memberof Autofill#
   * @param {WalkontableCellCoords} coords `WalkontableCellCoords` coord object.
   */
  showBorder(coords) {
    const topLeft = this.hot.getSelectedRange().getTopLeftCorner();
    const bottomRight = this.hot.getSelectedRange().getBottomRightCorner();
    const priv = privatePool.get(this);

    if (priv.settings('direction') !== 'horizontal' && (bottomRight.row < coords.row || topLeft.row > coords.row)) {
      coords = new WalkontableCellCoords(coords.row, bottomRight.col);

    } else if (priv.settings('direction') !== 'vertical') { // jscs:ignore disallowNotOperatorsInConditionals
      coords = new WalkontableCellCoords(bottomRight.row, coords.col);

    } else {
      // wrong direction
      return;
    }
    this.hot.view.wt.selections.fill.clear();
    this.hot.view.wt.selections.fill.add(this.hot.getSelectedRange().from);
    this.hot.view.wt.selections.fill.add(this.hot.getSelectedRange().to);
    this.hot.view.wt.selections.fill.add(coords);
    this.hot.view.render();
  }

  /**
   * Adds new rows if they are needed to continue auto-filling values
   * @function addNewRowIfNeeded
   * @memberof Autofill#
   */
  addNewRowIfNeeded() {
    const priv = privatePool.get(this);

    if (this.hot.view.wt.selections.fill.cellRange && this.addingStarted === false && priv.settings('autoInsertRow')) {
      const selection = this.hot.getSelected();
      const selectionsFillCorners = this.hot.view.wt.selections.fill.getCorners();
      const nrOfTableRows = this.hot.countRows();

      if (selection[2] < nrOfTableRows - 1 && selectionsFillCorners[2] === nrOfTableRows - 1) {
        this.addingStarted = true;

        this.hot._registerTimeout(setTimeout(() => {
          this.hot.alter('insert_row');
          this.addingStarted = false;
        }, 200));
      }
    }
  }

  onAfterCellCornerMouseDown() {
    this.handle.isDragged = 1;
    this.mouseDownOnCellCorner = true;
  }

  onBeforeCellMouseOver(coords) {
    if (this.mouseDownOnCellCorner && !this.hot.view.isMouseDown() && this.handle.isDragged) {
      this.handle.isDragged++;
      this.showBorder(coords);
      this.addNewRowIfNeeded();
    }
  }

  onMouseUp() {
    if (this.handle.isDragged) {
      if (this.handle.isDragged > 1) {
        this.apply();
      }
      this.handle.isDragged = 0;
      this.mouseDownOnCellCorner = false;
    }
  }

  getIfMouseDraggedOutside(event) {
    let tableBottom = offset(this.hot.table).top - (window.pageYOffset ||
      document.documentElement.scrollTop) + outerHeight(this.hot.table);
    let tableRight = offset(this.hot.table).left - (window.pageXOffset ||
      document.documentElement.scrollLeft) + outerWidth(this.hot.table);

    return event.clientY > tableBottom && event.clientX <= tableRight;
  }

  onMouseMove(event) {
    const priv = privatePool.get(this);

    if (this.addingStarted === false && this.handle.isDragged > 0 && this.getIfMouseDraggedOutside(event)) {
      this.mouseDragOutside = true;
      this.addingStarted = true;

    } else {
      this.mouseDragOutside = false;
    }

    if (this.mouseDragOutside && priv.settings('autoInsertRow')) {
      setTimeout(() => {
        this.addingStarted = false;
        this.hot.alter('insert_row');
      }, 200);
    }
  }

  /**
   * Destroy plugin instance.
   */
  destroy() {
    super.destroy();
  }
}

export {Autofill};

registerPlugin('autofill', Autofill);
<commit_msg>removed label from code #3257<commit_after>import BasePlugin from './../_base';
import {offset, outerHeight, outerWidth} from './../../helpers/dom/element';
import {eventManager as eventManagerObject} from './../../eventManager';
import {registerPlugin} from './../../plugins';
import {WalkontableCellCoords} from './../../3rdparty/walkontable/src/cell/coords';
import {getDeltas, settingsFactory, getDirectionAndRange} from './utils';
import {isObject} from './../../helpers/object';

const privatePool = new WeakMap();

/**
 * This plugin provides "drag-down" and "copy-down" functionalities, both operated
 * using the small square in the right bottom of the cell selection.
 *
 * "Drag-down" expands the value of the selected cells to the neighbouring
 * cells when you drag the small square in the corner.
 *
 * "Copy-down" copies the value of the selection to all empty cells
 * below when you double click the small square.
 *
 * @class Autofill
 * @plugin Autofill
 */

class Autofill extends BasePlugin {
  constructor(hotInstance) {
    super(hotInstance);

    this.eventManager = eventManagerObject(this);
    this.addingStarted = false;
    this.mouseDownOnCellCorner = false;
    this.mouseDragOutside = false;
    this.handle = {
      isDragged: 0,
      disabled: false
    };

    privatePool.set(this, {
      settings: settingsFactory(this.hot.getSettings().fillHandle)
    });
  }

  /**
   * Bind the events used by the plugin.
   *
   * @private
   */
  registerEvents() {
    this.eventManager.addEventListener(document, 'mouseup', () => this.onMouseUp());
    this.eventManager.addEventListener(document, 'mousemove', (event) => this.onMouseMove(event));
  }

  /**
   * Check if the plugin is enabled in the Handsontable settings.
   *
   * @returns {Boolean}
   */
  isEnabled() {
    return this.hot.getSettings().fillHandle === true || this.hot.getSettings().fillHandle === 'horizontal' ||
      this.hot.getSettings().fillHandle === 'vertical' || isObject(this.hot.getSettings().fillHandle);
  }

  /**
   * Enable plugin for this Handsontable instance.
   */
  enablePlugin() {
    if (this.enabled) {
      return;
    }

    this.registerEvents();

    this.addHook('afterOnCellCornerMouseDown', (event) => this.onAfterCellCornerMouseDown(event));
    this.addHook('beforeOnCellMouseOver', (event, coords, TD) => this.onBeforeCellMouseOver(coords));
    this.addHook('init', () => {
      this.hot.view.wt.wtSettings.settings.onCellCornerDblClick = () => {
        this.selectAdjacent();
      };
    });

    super.enablePlugin();
  }

  /**
   * Disable plugin for this Handsontable instance.
   */
  disablePlugin() {
    super.disablePlugin();
  }

  /**
   * Selects cells down to the last row in the left column, then fills down to that cell
   *
   * @function selectAdjacent
   * @memberof Autofill#
   */
  selectAdjacent() {
    let select;
    const data = this.hot.getData();
    var r, maxR, c;

    if (this.hot.selection.isMultiple()) {
      select = this.hot.view.wt.selections.area.getCorners();

    } else {
      select = this.hot.view.wt.selections.current.getCorners();
    }

    for (r = select[2] + 1; r < this.hot.countRows(); r++) {
      for (c = select[1]; c <= select[3]; c++) {
        if (data[r][c]) {
          return;
        }
      }
      if (!!data[r][select[1] - 1] || !!data[r][select[3] + 1]) {
        maxR = r;
      }
    }
    if (maxR) {
      this.hot.view.wt.selections.fill.clear();
      this.hot.view.wt.selections.fill.add(new WalkontableCellCoords(select[0], select[1]));
      this.hot.view.wt.selections.fill.add(new WalkontableCellCoords(maxR, select[3]));
      this.apply();
    }
  }

  /**
   * Apply fill values to the area in fill border, omitting the selection border
   *
   * @function apply
   * @memberof Autofill#
   */
  apply() {
    if (this.hot.view.wt.selections.fill.isEmpty()) {
      return;
    }

    const selectionsFillCorners = this.hot.view.wt.selections.fill.getCorners();
    let select;

    this.handle.isDragged = 0;
    this.hot.view.wt.selections.fill.clear();

    if (this.hot.selection.isMultiple()) {
      select = this.hot.view.wt.selections.area.getCorners();
    } else {
      select = this.hot.view.wt.selections.current.getCorners();
    }

    const {direction, start, end} = getDirectionAndRange(select, selectionsFillCorners);

    this.hot.runHooks('afterAutofillApplyValues', select, selectionsFillCorners);

    if (start && start.row > -1 && start.col > -1) {
      const selRange = {
        from: this.hot.getSelectedRange().from,
        to: this.hot.getSelectedRange().to,
      };

      const data = this.hot.getData(selRange.from.row, selRange.from.col, selRange.to.row, selRange.to.col);
      const deltas = getDeltas(start, end, data, direction);

      this.hot.runHooks('beforeAutofill', start, end, data);
      this.hot.populateFromArray(start.row, start.col, data, end.row, end.col, 'autofill', null, direction, deltas);

      this.hot.selection.setRangeStart(new WalkontableCellCoords(selectionsFillCorners[0], selectionsFillCorners[1]));
      this.hot.selection.setRangeEnd(new WalkontableCellCoords(selectionsFillCorners[2], selectionsFillCorners[3]));

    } else {
      // reset to avoid some range bug
      this.hot.selection.refreshBorders();
    }
  }

  /**
   * Show fill border
   *
   * @function showBorder
   * @memberof Autofill#
   * @param {WalkontableCellCoords} coords `WalkontableCellCoords` coord object.
   */
  showBorder(coords) {
    const topLeft = this.hot.getSelectedRange().getTopLeftCorner();
    const bottomRight = this.hot.getSelectedRange().getBottomRightCorner();
    const priv = privatePool.get(this);

    if (priv.settings('direction') !== 'horizontal' && (bottomRight.row < coords.row || topLeft.row > coords.row)) {
      coords = new WalkontableCellCoords(coords.row, bottomRight.col);

    } else if (priv.settings('direction') !== 'vertical') { // jscs:ignore disallowNotOperatorsInConditionals
      coords = new WalkontableCellCoords(bottomRight.row, coords.col);

    } else {
      // wrong direction
      return;
    }
    this.hot.view.wt.selections.fill.clear();
    this.hot.view.wt.selections.fill.add(this.hot.getSelectedRange().from);
    this.hot.view.wt.selections.fill.add(this.hot.getSelectedRange().to);
    this.hot.view.wt.selections.fill.add(coords);
    this.hot.view.render();
  }

  /**
   * Adds new rows if they are needed to continue auto-filling values
   * @function addNewRowIfNeeded
   * @memberof Autofill#
   */
  addNewRowIfNeeded() {
    const priv = privatePool.get(this);

    if (this.hot.view.wt.selections.fill.cellRange && this.addingStarted === false && priv.settings('autoInsertRow')) {
      const selection = this.hot.getSelected();
      const selectionsFillCorners = this.hot.view.wt.selections.fill.getCorners();
      const nrOfTableRows = this.hot.countRows();

      if (selection[2] < nrOfTableRows - 1 && selectionsFillCorners[2] === nrOfTableRows - 1) {
        this.addingStarted = true;

        this.hot._registerTimeout(setTimeout(() => {
          this.hot.alter('insert_row');
          this.addingStarted = false;
        }, 200));
      }
    }
  }

  onAfterCellCornerMouseDown() {
    this.handle.isDragged = 1;
    this.mouseDownOnCellCorner = true;
  }

  onBeforeCellMouseOver(coords) {
    if (this.mouseDownOnCellCorner && !this.hot.view.isMouseDown() && this.handle.isDragged) {
      this.handle.isDragged++;
      this.showBorder(coords);
      this.addNewRowIfNeeded();
    }
  }

  onMouseUp() {
    if (this.handle.isDragged) {
      if (this.handle.isDragged > 1) {
        this.apply();
      }
      this.handle.isDragged = 0;
      this.mouseDownOnCellCorner = false;
    }
  }

  getIfMouseDraggedOutside(event) {
    let tableBottom = offset(this.hot.table).top - (window.pageYOffset ||
      document.documentElement.scrollTop) + outerHeight(this.hot.table);
    let tableRight = offset(this.hot.table).left - (window.pageXOffset ||
      document.documentElement.scrollLeft) + outerWidth(this.hot.table);

    return event.clientY > tableBottom && event.clientX <= tableRight;
  }

  onMouseMove(event) {
    const priv = privatePool.get(this);

    if (this.addingStarted === false && this.handle.isDragged > 0 && this.getIfMouseDraggedOutside(event)) {
      this.mouseDragOutside = true;
      this.addingStarted = true;

    } else {
      this.mouseDragOutside = false;
    }

    if (this.mouseDragOutside && priv.settings('autoInsertRow')) {
      setTimeout(() => {
        this.addingStarted = false;
        this.hot.alter('insert_row');
      }, 200);
    }
  }

  /**
   * Destroy plugin instance.
   */
  destroy() {
    super.destroy();
  }
}

export {Autofill};

registerPlugin('autofill', Autofill);

{'fraction_non_alphanumeric': 0.1440909090909091, 'fraction_numerical': 0.004090909090909091, 'mean_word_length': 3.0695953757225434, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3809091', 'n_tokens_mistral': 5754, 'n_tokens_neox': 5584, 'n_words': 1078}