<commit_before>import React, { Component, PropTypes } from 'react'
import classNames from 'classnames'
import Avatar from '../assets/Avatar'
import Emoji from '../assets/Emoji'
import Completion from './Completion'
import { getPositionFromSelection } from '../editor/SelectionUtil'
import { addKeyObject, removeKeyObject } from '../interface/KeyComponent'
import { addResizeObject, removeResizeObject } from '../interface/ResizeComponent'

export const emojiRegex = /\s?:{1}(\w+|\+|-):{0}$/
export const userRegex = /\s?@{1}\w+/

export default class Completer extends Component {

  static propTypes = {
    className: PropTypes.string,
    completions: PropTypes.object.isRequired,
    onCancel: PropTypes.func.isRequired,
    onCompletion: PropTypes.func.isRequired,
  }

  componentWillMount() {
    this.state = {
      selectedIndex: 0,
      viewportDeviceSize: null,
    }
  }

  componentDidMount() {
    addKeyObject(this)
    addResizeObject(this)
  }

  componentWillUnmount() {
    removeKeyObject(this)
    removeResizeObject(this)
  }

  onKeyDown(e) {
    if ((!e.shiftKey && e.which === 9) || e.which === 40) {
      e.preventDefault()
      this.nextSelection()
    } else if ((e.shiftKey && e.which === 9) || e.which === 38) {
      e.preventDefault()
      this.prevSelection()
    } else if (e.which === 13) {
      e.preventDefault()
      this.submit()
    } else if (e.which === 27) {
      e.preventDefault()
      this.props.onCancel()
    }
  }

  onResize({ viewportDeviceSize }) {
    this.setState({ viewportDeviceSize })
  }

  nextSelection() {
    const { completions } = this.props
    let { selectedIndex } = this.state
    selectedIndex++
    if (selectedIndex > completions.data.length - 1) selectedIndex = 0
    this.setState({ selectedIndex })
  }

  prevSelection() {
    const { completions } = this.props
    let { selectedIndex } = this.state
    selectedIndex--
    if (selectedIndex < 0) selectedIndex = completions.data.length - 1
    this.setState({ selectedIndex })
  }

  submit() {
    const { onCompletion } = this.props
    const { selectedIndex } = this.state
    onCompletion({ value: this.refs[`completion_${selectedIndex}`].getValue() })
  }

  renderUsers() {
    const { completions, onCompletion } = this.props
    const { selectedIndex } = this.state
    return (
      completions.data.map((completion, i) =>
        <Completion
          className={ i === selectedIndex ? 'active' : null }
          key={ `completion_${i}` }
          asset={ <Avatar classList="tiny" sources={{ tmp: { url: completion.imageUrl } }} />}
          label={ `@${completion.name}` }
          ref={ `completion_${i}` }
          onClick={ onCompletion }
        />
      )
    )
  }

  renderEmoji() {
    const { completions, onCompletion } = this.props
    const { selectedIndex } = this.state
    return (
      completions.data.map((completion, i) =>
        <Completion
          className={ i === selectedIndex ? 'active' : null }
          key={ `completion_${i}` }
          asset={ <Emoji key={ completion.name } src={ completion.imageUrl } />}
          label={ `:${completion.name}:` }
          ref={ `completion_${i}` }
          onClick={ onCompletion }
        />
      )
    )
  }

  render() {
    const { className, completions } = this.props
    const { viewportDeviceSize } = this.state
    if (!completions || !completions.data || !completions.data.length) {
      return null
    }
    const pos = getPositionFromSelection()
    const coords = pos || { top: 0, left: 0 }
    const top = viewportDeviceSize === 'mobile' ? coords.top + 45 : coords.top + 20
    const left = viewportDeviceSize === 'mobile' ? 0 : coords.left
    const style = pos ? { top, left } : null
    return (
      <div style={ style } className={ classNames(className, 'Completer') }>
        { completions.type === 'user' ? this.renderUsers() : this.renderEmoji() }
      </div>
    )
  }
}
<commit_msg>use custom logic for mobile devices, so the emoji picker 'pins to bottom'<commit_after>import React, { Component, PropTypes } from 'react'
import classNames from 'classnames'
import Avatar from '../assets/Avatar'
import Emoji from '../assets/Emoji'
import Completion from './Completion'
import { getPositionFromSelection } from '../editor/SelectionUtil'
import { addKeyObject, removeKeyObject } from '../interface/KeyComponent'
import { addResizeObject, removeResizeObject } from '../interface/ResizeComponent'

export const emojiRegex = /\s?:{1}(\w+|\+|-):{0}$/
export const userRegex = /\s?@{1}\w+/

export default class Completer extends Component {

  static propTypes = {
    className: PropTypes.string,
    completions: PropTypes.object.isRequired,
    onCancel: PropTypes.func.isRequired,
    onCompletion: PropTypes.func.isRequired,
  }

  componentWillMount() {
    this.state = {
      selectedIndex: 0,
      viewportDeviceSize: null,
    }
  }

  componentDidMount() {
    addKeyObject(this)
    addResizeObject(this)
  }

  componentWillUnmount() {
    removeKeyObject(this)
    removeResizeObject(this)
  }

  onKeyDown(e) {
    if ((!e.shiftKey && e.which === 9) || e.which === 40) {
      e.preventDefault()
      this.nextSelection()
    } else if ((e.shiftKey && e.which === 9) || e.which === 38) {
      e.preventDefault()
      this.prevSelection()
    } else if (e.which === 13) {
      e.preventDefault()
      this.submit()
    } else if (e.which === 27) {
      e.preventDefault()
      this.props.onCancel()
    }
  }

  onResize({ viewportDeviceSize }) {
    this.setState({ viewportDeviceSize })
  }

  nextSelection() {
    const { completions } = this.props
    let { selectedIndex } = this.state
    selectedIndex++
    if (selectedIndex > completions.data.length - 1) selectedIndex = 0
    this.setState({ selectedIndex })
  }

  prevSelection() {
    const { completions } = this.props
    let { selectedIndex } = this.state
    selectedIndex--
    if (selectedIndex < 0) selectedIndex = completions.data.length - 1
    this.setState({ selectedIndex })
  }

  submit() {
    const { onCompletion } = this.props
    const { selectedIndex } = this.state
    onCompletion({ value: this.refs[`completion_${selectedIndex}`].getValue() })
  }

  renderUsers() {
    const { completions, onCompletion } = this.props
    const { selectedIndex } = this.state
    return (
      completions.data.map((completion, i) =>
        <Completion
          className={ i === selectedIndex ? 'active' : null }
          key={ `completion_${i}` }
          asset={ <Avatar classList="tiny" sources={{ tmp: { url: completion.imageUrl } }} />}
          label={ `@${completion.name}` }
          ref={ `completion_${i}` }
          onClick={ onCompletion }
        />
      )
    )
  }

  renderEmoji() {
    const { completions, onCompletion } = this.props
    const { selectedIndex } = this.state
    return (
      completions.data.map((completion, i) =>
        <Completion
          className={ i === selectedIndex ? 'active' : null }
          key={ `completion_${i}` }
          asset={ <Emoji key={ completion.name } src={ completion.imageUrl } />}
          label={ `:${completion.name}:` }
          ref={ `completion_${i}` }
          onClick={ onCompletion }
        />
      )
    )
  }

  render() {
    const { className, completions } = this.props
    const { viewportDeviceSize } = this.state
    if (!completions || !completions.data || !completions.data.length) {
      return null
    }

    let style = null
    const pos = getPositionFromSelection()
    if (viewportDeviceSize === 'mobile') {
      const height = 41
      const halfHeight = 21
      const numCompletions = completions.data.length
      if (numCompletions < 4) {
        style = { bottom: -halfHeight - height * (3 - numCompletions) }
      } else {
        style = { bottom: 0 }
      }
    } else if (pos) {
      style = { top: pos.top + 20, left: pos.left }
    }
    return (
      <div style={ style } className={ classNames(className, 'Completer') }>
        { completions.type === 'user' ? this.renderUsers() : this.renderEmoji() }
      </div>
    )
  }
}

{'fraction_non_alphanumeric': 0.1432449105490438, 'fraction_numerical': 0.0064157927205428745, 'mean_word_length': 2.6645569620253164, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 21, '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': '3297625', 'n_tokens_mistral': 2489, 'n_tokens_neox': 2450, 'n_words': 556}