<commit_before>`import className from '../mixins/class-name'`
`import animationSupport from '../mixins/animation-support'`
`import mobileDetection from '../mixins/mobile-detection'`
`import preventPageScroll from '../mixins/prevent-page-scroll'`
`import poplistLayout from '../templates/eui-poplist'`
`import itemViewClassTemplate from '../templates/eui-poplist-option'`

poplist = Em.Component.extend className, animationSupport, mobileDetection, preventPageScroll,
  layout: poplistLayout
  classNames: ['eui-poplist']
  classNameBindings: ['isOpen::eui-closing', 'isMobileDevice:eui-touch']
  attributeBindings: ['tabindex']
  tagName: 'eui-poplist'

  baseClass: 'poplist'
  style: 'default'

  animationClass: 'euiPoplist'


  # Width of the poplist. Because list-view uses absolute positioning we can not
  # rely on the content to push the poplist wider so the user needs a way to
  # specify it

  listWidth: null


  # Controls the vertical height and row height for the list-view component

  listHeight: '80'
  listRowHeight: Ember.computed 'isMobileDevice', ->
    if @get 'isMobileDevice' then return '30' else return '20'


  # Controls whether poplist should be a modal if opened on a mobile device

  modalOnMobile: false


  # Path to the string that should be used as the label

  labelPath: 'label'


  # Options user should select from

  options: null


  # String the user wants to filter by

  searchString: null


  # Index of option currently highlighted

  highlightedIndex: -1


  # If the poplist is opened using the keyboard then we use this value to
  # restore the focus where it was after the poplist closes.

  previousFocus: null


  # Option that is currently highlighted

  highlighted: Ember.computed 'highlightedIndex', 'filteredOptions', (key, value) ->
    options = @get 'filteredOptions'

    # setter
    if arguments.length is 2
      index = options.indexOf value
      @set 'highlightedIndex', index
      value

    # getter
    else
      index = @get 'highlightedIndex'
      options.objectAt index


  hide: ->
    @animateOut({
      target: @get('targetObject').$()
      complete: => @breakdown()
    })


  setup: (->
    @setPoplistMinWidth()

    component = @.$().find('.eui-component')

    # Positions calendar using fixed positioning
    if @get('isMobileDevice') && @get('modalOnMobile')
      Em.run.next @, -> component.position {
        my: "center center",
        at: "center center",
        of: $(window)
      }
    else
      Em.run.next @, -> component.position {
        my: "right top",
        at: "right bottom",
        of: @get('targetObject').$(),
        collision: 'flipfit'
      }

    @animateIn()

    @set 'isOpen', true
    @set 'previousFocus', $(document.activeElement)

    # Focus on search input to ensure we can catch keyboard input. Do this after
    # the poplist is positioned to ensure it is visible. Don't do this on
    # mobile because old android versions will open up the keyboard.
    unless @get 'isMobileDevice'
      Ember.run.next this, -> @focusOnSearch()

    # Set poplist width
    @updateListWidthCss()

    # Ensure the selected option is visible and center it
    Ember.run.next this, -> @scrollToSelection @get('options').indexOf(@get 'selection'), true

    @disablePageScroll()
  ).on 'didInsertElement'


  breakdown: ->
    @setProperties { isOpen: false, highlightedIndex: -1 }

    @get('previousFocus').focus()

    @enablePageScroll()
    @destroy()


  # Set poplist width to the user specified width, but enforce a min width of
  # the parent button

  setPoplistMinWidth: ->
    element = @get('targetObject').$()
    poplistElement = @.$().find('.eui-component')

    elementWidthMinuspoplistPadding =
      element.width() -
      parseFloat(poplistElement.css('paddingLeft')) -
      parseFloat(poplistElement.css('paddingRight'))

    poplistElement.css('min-width', elementWidthMinuspoplistPadding)


  # Because we are manually setting other css on the element we can't use
  # bindings to update it automatically and have to do so manually

  updateListWidthCss: ->
    component = @.$().find('.eui-component')

    if @get('isMobileDevice') && @get('modalOnMobile')
      component.css 'width', '80%'
    else
      listWidth = @get 'listWidth'
      component.css 'width', listWidth


  # Focuses on search input so we can catch key input

  focusOnSearch: ->
    @$().find('input:first').focus()


  # Set the selection back to the first option if the users changes the search
  # query
  # TODO: This doesn't fire the bindings on the listView correctly and you end
  # up with multiple items highlighted.

  searchStringDidChange: (->
    @set 'highlightedIndex', 0 if @get 'searchString'
  ).observes 'searchString'


  # Filter the option list based on the query entered into the search box

  filteredOptions: (->
    options = @get 'options'
    query = @get 'searchString'

    return [] unless options
    return options unless query

    labelPath = @get 'labelPath'

    escapedQuery = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
    regex = new RegExp(escapedQuery, 'i')

    filteredOptions = options.filter (item, index, self) ->
      label = item.get?(labelPath) or item[labelPath]
      regex.test(label) if label

    return filteredOptions
  ).property 'options.@each', 'labelPath', 'searchString'


  hasNoOptions: Ember.computed.empty 'filteredOptions'


  # Updates the list-view's height based on the number of options

  optionsLengthDidChange: (->
    @updateListHeight()
  ).observes 'filteredOptions.length'


  updateListHeight: ->
    optionCount = @get 'filteredOptions.length'
    rowHeight = @get 'listRowHeight'

    if optionCount <= 12
      @set 'listHeight', optionCount * rowHeight
    else
      @set 'listHeight', 10 * rowHeight


  # Scroll the list to make sure the given option is visible.
  # Copied from https://github.com/Addepar/ember-widgets/

  scrollToSelection: (index, center) ->
    $listView  = @.$('.ember-list-view')
    listView   = Ember.View.views[$listView.attr('id')]
    startIndex = listView._startingIndex()
    numRows    = listView._childViewCount() - 1
    endIndex   = startIndex + numRows

    if index is 0
      $listView.scrollTop 0
    else if index < startIndex
      $listView.scrollTop index * @get 'listRowHeight'
    else if index >= endIndex
      if center
        $listView.scrollTop (index - (numRows / 2)) * @get 'listRowHeight'
      else
        $listView.scrollTop (index - numRows + 1) * @get 'listRowHeight'


  # Keyboard controls

  KEY_MAP:
    27: 'escapePressed'
    13: 'enterPressed'
    38: 'upArrowPressed'
    40: 'downArrowPressed'


  keyUp: (event) ->
    keyMap = @get 'KEY_MAP'<commit_msg>fix page scrolling when down button is pressed with poplist open<commit_after>`import className from '../mixins/class-name'`
`import animationSupport from '../mixins/animation-support'`
`import mobileDetection from '../mixins/mobile-detection'`
`import preventPageScroll from '../mixins/prevent-page-scroll'`
`import poplistLayout from '../templates/eui-poplist'`
`import itemViewClassTemplate from '../templates/eui-poplist-option'`

poplist = Em.Component.extend className, animationSupport, mobileDetection, preventPageScroll,
  layout: poplistLayout
  classNames: ['eui-poplist']
  classNameBindings: ['isOpen::eui-closing', 'isMobileDevice:eui-touch']
  attributeBindings: ['tabindex']
  tagName: 'eui-poplist'

  baseClass: 'poplist'
  style: 'default'

  animationClass: 'euiPoplist'


  # Width of the poplist. Because list-view uses absolute positioning we can not
  # rely on the content to push the poplist wider so the user needs a way to
  # specify it

  listWidth: null


  # Controls the vertical height and row height for the list-view component

  listHeight: '80'
  listRowHeight: Ember.computed 'isMobileDevice', ->
    if @get 'isMobileDevice' then return '30' else return '20'


  # Controls whether poplist should be a modal if opened on a mobile device

  modalOnMobile: false


  # Path to the string that should be used as the label

  labelPath: 'label'


  # Options user should select from

  options: null


  # String the user wants to filter by

  searchString: null


  # Index of option currently highlighted

  highlightedIndex: -1


  # If the poplist is opened using the keyboard then we use this value to
  # restore the focus where it was after the poplist closes.

  previousFocus: null


  # Option that is currently highlighted

  highlighted: Ember.computed 'highlightedIndex', 'filteredOptions', (key, value) ->
    options = @get 'filteredOptions'

    # setter
    if arguments.length is 2
      index = options.indexOf value
      @set 'highlightedIndex', index
      value

    # getter
    else
      index = @get 'highlightedIndex'
      options.objectAt index


  hide: ->
    @animateOut({
      target: @get('targetObject').$()
      complete: => @breakdown()
    })


  setup: (->
    @setPoplistMinWidth()

    component = @.$().find('.eui-component')

    # Positions calendar using fixed positioning
    if @get('isMobileDevice') && @get('modalOnMobile')
      Em.run.next @, -> component.position {
        my: "center center",
        at: "center center",
        of: $(window)
      }
    else
      Em.run.next @, -> component.position {
        my: "right top",
        at: "right bottom",
        of: @get('targetObject').$(),
        collision: 'flipfit'
      }

    @animateIn()

    @set 'isOpen', true
    @set 'previousFocus', $(document.activeElement)

    # Focus on search input to ensure we can catch keyboard input. Do this after
    # the poplist is positioned to ensure it is visible. Don't do this on
    # mobile because old android versions will open up the keyboard.
    unless @get 'isMobileDevice'
      Ember.run.next this, -> @focusOnSearch()

    # Set poplist width
    @updateListWidthCss()

    # Ensure the selected option is visible and center it
    Ember.run.next this, -> @scrollToSelection @get('options').indexOf(@get 'selection'), true

    @disablePageScroll()
  ).on 'didInsertElement'


  breakdown: ->
    @setProperties { isOpen: false, highlightedIndex: -1 }

    @get('previousFocus').focus()

    @enablePageScroll()
    @destroy()


  # Set poplist width to the user specified width, but enforce a min width of
  # the parent button

  setPoplistMinWidth: ->
    element = @get('targetObject').$()
    poplistElement = @.$().find('.eui-component')

    elementWidthMinuspoplistPadding =
      element.width() -
      parseFloat(poplistElement.css('paddingLeft')) -
      parseFloat(poplistElement.css('paddingRight'))

    poplistElement.css('min-width', elementWidthMinuspoplistPadding)


  # Because we are manually setting other css on the element we can't use
  # bindings to update it automatically and have to do so manually

  updateListWidthCss: ->
    component = @.$().find('.eui-component')

    if @get('isMobileDevice') && @get('modalOnMobile')
      component.css 'width', '80%'
    else
      listWidth = @get 'listWidth'
      component.css 'width', listWidth


  # Focuses on search input so we can catch key input

  focusOnSearch: ->
    @$().find('input:first').focus()


  # Set the selection back to the first option if the users changes the search
  # query
  # TODO: This doesn't fire the bindings on the listView correctly and you end
  # up with multiple items highlighted.

  searchStringDidChange: (->
    @set 'highlightedIndex', 0 if @get 'searchString'
  ).observes 'searchString'


  # Filter the option list based on the query entered into the search box

  filteredOptions: (->
    options = @get 'options'
    query = @get 'searchString'

    return [] unless options
    return options unless query

    labelPath = @get 'labelPath'

    escapedQuery = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
    regex = new RegExp(escapedQuery, 'i')

    filteredOptions = options.filter (item, index, self) ->
      label = item.get?(labelPath) or item[labelPath]
      regex.test(label) if label

    return filteredOptions
  ).property 'options.@each', 'labelPath', 'searchString'


  hasNoOptions: Ember.computed.empty 'filteredOptions'


  # Updates the list-view's height based on the number of options

  optionsLengthDidChange: (->
    @updateListHeight()
  ).observes 'filteredOptions.length'


  updateListHeight: ->
    optionCount = @get 'filteredOptions.length'
    rowHeight = @get 'listRowHeight'

    if optionCount <= 12
      @set 'listHeight', optionCount * rowHeight
    else
      @set 'listHeight', 10 * rowHeight


  # Scroll the list to make sure the given option is visible.
  # Copied from https://github.com/Addepar/ember-widgets/

  scrollToSelection: (index, center) ->
    $listView  = @.$('.ember-list-view')
    listView   = Ember.View.views[$listView.attr('id')]
    startIndex = listView._startingIndex()
    numRows    = listView._childViewCount() - 1
    endIndex   = startIndex + numRows

    if index is 0
      $listView.scrollTop 0
    else if index < startIndex
      $listView.scrollTop index * @get 'listRowHeight'
    else if index >= endIndex
      if center
        $listView.scrollTop (index - (numRows / 2)) * @get 'listRowHeight'
      else
        $listView.scrollTop (index - numRows + 1) * @get 'listRowHeight'


  # Keyboard controls

  KEY_MAP:
    27: 'escapePressed'
    13: 'enterPressed'
    38: 'upArrowPressed'
    40: 'downArrowPressed'


  keyDown: (event) ->
    keyMap = @get 'KEY_MAP'
{'fraction_non_alphanumeric': 0.11185914034179181, 'fraction_numerical': 0.004290892949618998, 'mean_word_length': 3.2072829131652663, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 45, 'https://': 2, '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': '2994102', 'n_tokens_mistral': 4145, 'n_tokens_neox': 3883, 'n_words': 1261}