<commit_before>(($, window, document) ->

  pluginName = "immybox"
  defaults =
    choices: []
    blankIfNull: true
    maxResults: 50
    filterFn: (query) ->
      (choice) ->
        choice.text.indexOf(query) >= 0

  _id = 1
  nextId = -> "#{pluginName}_#{_id++}"

  addCommas = (nStr) ->
    nStr += '';
    x = nStr.split '.'
    x1 = x[0]
    x2 = if x.length > 1 then '.' + x[1] else ''
    rgx = /(\d+)(\d{3})/
    while (rgx.test(x1))
      x1 = x1.replace rgx, '$1' + ',' + '$2'
    return x1 + x2

  # TODO get a proper escape function
  esc = (x) -> x

  class ImmyBox

    constructor: (element, options) ->
      self = @

      @element = $ element
      @element.addClass pluginName

      @_defaults = defaults
      @_name = pluginName

      @options = $.extend {}, defaults, options
      @choices = @options.choices
      @selectedChoice = null

      # init with the value that's in the text box
      @selectChoiceByValue @element.val()

      id = nextId()
      $('body').append "<div id=#{id} class='#{pluginName}_results'></div>"
      @queryResultArea = $ "##{id}"
      @hideResults()

      @_val = @element.val() # to keep track of what WAS in the text box

      @queryResultArea.on 'mousedown', 'li.choice', ->
        value = $(@).data 'value'
        self.selectChoiceByValue value
        self.hideResults()
        @_val = self.element.val()
        setTimeout -> # wait for mouseup event a focus to be lost
          self.element.focus()
        , 100

      @queryResultArea.on 'mouseenter', 'li.choice', ->
        highlightedChoice = self.queryResultArea.find('li.choice.active')
        highlightedChoice.removeClass 'active'
        $(@).addClass 'active'

      @element.on 'keyup change search', @doQuery
      @element.on 'keydown', @doSelection
      @element.on 'blur', @revert
      $(window).on 'resize', @reposition

    ###################
    # event listeners #
    ###################

    # @element.on 'keyup change search'
    # perform a query on the choices
    doQuery: =>
      query = @element.val()
      if @_val isnt query # user has changed input value, do a search and display the search results
        @_val = query
        if query is ''
          @hideResults()
        else
          filteredChoices = (@choices.filter @options.filterFn query)
          truncatedChoices = filteredChoices[0...@options.maxResults]
          difference = filteredChoices.length - truncatedChoices.length
          results = truncatedChoices.map (choice) -> "<li class='choice' data-value='#{esc choice.value}'>#{esc choice.text}</li>"
          info = if difference > 0
            "<p class='moreinfo'>showing #{addCommas truncatedChoices.length} of #{addCommas filteredChoices.length}</p>"
          else if results.length is 0
            "<p class='noresults'>no matches</p>"
          else
            ''
          @queryResultArea.html "<ul>#{results.join '\n'}</ul>#{info}"
          @queryResultArea.find('li.choice:first').addClass 'active'
          @showResults()

    # @element.on 'keydown'
    # select the highlighted choice
    doSelection: (e) =>
      if @queryResultArea.is(':visible')
        switch e.which
          when 9 # tab
            @selectHighlightedChoice()
          when 13 # enter
            e.preventDefault() # prevent form from submitting (i think; test this!)
            @selectHighlightedChoice()
          when 38 # up
            e.preventDefault() # prevent cursor from moving
            @highlightPreviousChoice()
          when 40 # down
            e.preventDefault() # prevent cursor from moving
            @highlightNextChoice()

    # @element.on 'blur'
    # revert or set to null after losing focus<commit_msg>Allow escape to cancel out. Fixes #14<commit_after>(($, window, document) ->

  pluginName = "immybox"
  defaults =
    choices: []
    blankIfNull: true
    maxResults: 50
    filterFn: (query) ->
      # default filer function does case insensitive "contains" matching
      (choice) ->
        choice.text.toLowerCase().indexOf(query.toLowerCase()) >= 0

  _id = 1
  nextId = -> "#{pluginName}_#{_id++}"

  addCommas = (nStr) ->
    nStr += '';
    x = nStr.split '.'
    x1 = x[0]
    x2 = if x.length > 1 then '.' + x[1] else ''
    rgx = /(\d+)(\d{3})/
    while (rgx.test(x1))
      x1 = x1.replace rgx, '$1' + ',' + '$2'
    return x1 + x2

  # TODO get a proper escape function
  esc = (x) -> x

  class ImmyBox

    constructor: (element, options) ->
      self = @

      @element = $ element
      @element.addClass pluginName

      @_defaults = defaults
      @_name = pluginName

      @options = $.extend {}, defaults, options
      @choices = @options.choices
      @selectedChoice = null

      # init with the value that's in the text box
      @selectChoiceByValue @element.val()

      id = nextId()
      $('body').append "<div id=#{id} class='#{pluginName}_results'></div>"
      @queryResultArea = $ "##{id}"
      @hideResults()

      @_val = @element.val() # to keep track of what WAS in the text box

      @queryResultArea.on 'mousedown', 'li.choice', ->
        value = $(@).data 'value'
        self.selectChoiceByValue value
        self.hideResults()
        @_val = self.element.val()
        setTimeout -> # wait for mouseup event a focus to be lost
          self.element.focus()
        , 100

      @queryResultArea.on 'mouseenter', 'li.choice', ->
        highlightedChoice = self.queryResultArea.find('li.choice.active')
        highlightedChoice.removeClass 'active'
        $(@).addClass 'active'

      @element.on 'keyup change search', @doQuery
      @element.on 'keydown', @doSelection
      @element.on 'blur', @revert
      $(window).on 'resize', @reposition

    ###################
    # event listeners #
    ###################

    # @element.on 'keyup change search'
    # perform a query on the choices
    doQuery: =>
      query = @element.val()
      if @_val isnt query # user has changed input value, do a search and display the search results
        @_val = query
        if query is ''
          @hideResults()
        else
          filteredChoices = (@choices.filter @options.filterFn query)
          truncatedChoices = filteredChoices[0...@options.maxResults]
          difference = filteredChoices.length - truncatedChoices.length
          results = truncatedChoices.map (choice) -> "<li class='choice' data-value='#{esc choice.value}'>#{esc choice.text}</li>"
          info = if difference > 0
            "<p class='moreinfo'>showing #{addCommas truncatedChoices.length} of #{addCommas filteredChoices.length}</p>"
          else if results.length is 0
            "<p class='noresults'>no matches</p>"
          else
            ''
          @queryResultArea.html "<ul>#{results.join '\n'}</ul>#{info}"
          @queryResultArea.find('li.choice:first').addClass 'active'
          @showResults()

    # @element.on 'keydown'
    # select the highlighted choice
    doSelection: (e) =>
      if e.which is 27
        @display()
        @hideResults()
      if @queryResultArea.is(':visible')
        switch e.which
          when 9 # tab
            @selectHighlightedChoice()
          when 13 # enter
            e.preventDefault() # prevent form from submitting (i think; test this!)
            @selectHighlightedChoice()
          when 38 # up
            e.preventDefault() # prevent cursor from moving
            @highlightPreviousChoice()
          when 40 # down
            e.preventDefault() # prevent cursor from moving
            @highlightNextChoice()

    # @element.on 'blur'
    # revert or set to null after losing focus
{'fraction_non_alphanumeric': 0.14012572027239392, 'fraction_numerical': 0.008381351492928235, 'mean_word_length': 2.2664670658682633, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, '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': '314627', 'n_tokens_mistral': 2305, 'n_tokens_neox': 2216, 'n_words': 607}