<commit_before>
import Debug from 'debug'
import React from 'react'
import Types from 'prop-types'
import getWindow from 'get-window'
import logger from 'slate-dev-logger'
import throttle from 'lodash.throttle'

import EVENT_HANDLERS from '../constants/event-handlers'
import Node from './node'
import findDOMRange from '../utils/find-dom-range'
import findRange from '../utils/find-range'
import scrollToSelection from '../utils/scroll-to-selection'
import {
  IS_FIREFOX,
  IS_IOS,
  IS_ANDROID,
  SUPPORTED_EVENTS
} from '../constants/environment'

/**
 * Debug.
 *
 * @type {Function}
 */

const debug = Debug('slate:content')

/**
 * Content.
 *
 * @type {Component}
 */

class Content extends React.Component {

  /**
   * Property types.
   *
   * @type {Object}
   */

  static propTypes = {
    autoCorrect: Types.bool.isRequired,
    autoFocus: Types.bool.isRequired,
    children: Types.any.isRequired,
    className: Types.string,
    editor: Types.object.isRequired,
    readOnly: Types.bool.isRequired,
    role: Types.string,
    spellCheck: Types.bool.isRequired,
    style: Types.object,
    tabIndex: Types.number,
    tagName: Types.string,
  }

  /**
   * Default properties.
   *
   * @type {Object}
   */

  static defaultProps = {
    style: {},
    tagName: 'div',
  }

  /**
   * Constructor.
   *
   * @param {Object} props
   */

  constructor(props) {
    super(props)
    this.tmp = {}
    this.tmp.key = 0
    this.tmp.isUpdatingSelection = false

    EVENT_HANDLERS.forEach((handler) => {
      this[handler] = (event) => {
        this.onEvent(handler, event)
      }
    })
  }

  /**
   * When the editor first mounts in the DOM we need to:
   *
   *   - Add native DOM event listeners.
   *   - Update the selection, in case it starts focused.
   *   - Focus the editor if `autoFocus` is set.
   */

  componentDidMount = () => {
    const { editor } = this.props
    const window = getWindow(this.element)

    window.document.addEventListener('selectionchange', this.onNativeSelectionChange)

    // COMPAT: Restrict scope of `beforeinput` to mobile.
    if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) {
      this.element.addEventListener('beforeinput', this.onNativeBeforeInput)
    }

    this.updateSelection()

    if (this.props.autoFocus) {
      editor.focus()
    }
  }

  /**
   * When unmounting, remove DOM event listeners.
   */

  componentWillUnmount() {
    const window = getWindow(this.element)

    window.document.removeEventListener('selectionchange', this.onNativeSelectionChange)

    // COMPAT: Restrict scope of `beforeinput` to mobile.
    if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) {
      this.element.removeEventListener('beforeinput', this.onNativeBeforeInput)
    }
  }

  /**
   * On update, update the selection.
   */

  componentDidUpdate = () => {
    this.updateSelection()
  }

  /**
   * Update the native DOM selection to reflect the internal model.
   */

  updateSelection = () => {
    const { editor } = this.props<commit_msg>Don't attempt to remove event listeners from non-existent window (#1495)<commit_after>
import Debug from 'debug'
import React from 'react'
import Types from 'prop-types'
import getWindow from 'get-window'
import logger from 'slate-dev-logger'
import throttle from 'lodash.throttle'

import EVENT_HANDLERS from '../constants/event-handlers'
import Node from './node'
import findDOMRange from '../utils/find-dom-range'
import findRange from '../utils/find-range'
import scrollToSelection from '../utils/scroll-to-selection'
import {
  IS_FIREFOX,
  IS_IOS,
  IS_ANDROID,
  SUPPORTED_EVENTS
} from '../constants/environment'

/**
 * Debug.
 *
 * @type {Function}
 */

const debug = Debug('slate:content')

/**
 * Content.
 *
 * @type {Component}
 */

class Content extends React.Component {

  /**
   * Property types.
   *
   * @type {Object}
   */

  static propTypes = {
    autoCorrect: Types.bool.isRequired,
    autoFocus: Types.bool.isRequired,
    children: Types.any.isRequired,
    className: Types.string,
    editor: Types.object.isRequired,
    readOnly: Types.bool.isRequired,
    role: Types.string,
    spellCheck: Types.bool.isRequired,
    style: Types.object,
    tabIndex: Types.number,
    tagName: Types.string,
  }

  /**
   * Default properties.
   *
   * @type {Object}
   */

  static defaultProps = {
    style: {},
    tagName: 'div',
  }

  /**
   * Constructor.
   *
   * @param {Object} props
   */

  constructor(props) {
    super(props)
    this.tmp = {}
    this.tmp.key = 0
    this.tmp.isUpdatingSelection = false

    EVENT_HANDLERS.forEach((handler) => {
      this[handler] = (event) => {
        this.onEvent(handler, event)
      }
    })
  }

  /**
   * When the editor first mounts in the DOM we need to:
   *
   *   - Add native DOM event listeners.
   *   - Update the selection, in case it starts focused.
   *   - Focus the editor if `autoFocus` is set.
   */

  componentDidMount = () => {
    const { editor } = this.props
    const window = getWindow(this.element)

    window.document.addEventListener('selectionchange', this.onNativeSelectionChange)

    // COMPAT: Restrict scope of `beforeinput` to mobile.
    if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) {
      this.element.addEventListener('beforeinput', this.onNativeBeforeInput)
    }

    this.updateSelection()

    if (this.props.autoFocus) {
      editor.focus()
    }
  }

  /**
   * When unmounting, remove DOM event listeners.
   */

  componentWillUnmount() {
    const window = getWindow(this.element)

    if (window) {
      window.document.removeEventListener('selectionchange', this.onNativeSelectionChange)
    }

    // COMPAT: Restrict scope of `beforeinput` to mobile.
    if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) {
      this.element.removeEventListener('beforeinput', this.onNativeBeforeInput)
    }
  }

  /**
   * On update, update the selection.
   */

  componentDidUpdate = () => {
    this.updateSelection()
  }

  /**
   * Update the native DOM selection to reflect the internal model.
   */

  updateSelection = () => {
    const { editor } = this.props
{'fraction_non_alphanumeric': 0.1274557558045137, 'fraction_numerical': 0.000974184120798831, 'mean_word_length': 2.8815374921235035, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, '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': '2642561', 'n_tokens_mistral': 1979, 'n_tokens_neox': 1916, 'n_words': 452}