<commit_before>###
An input area with a dropdown arrow, which invokes a popup.
###

class window.ComboBox extends PopupSource

  inherited:
    closeOnInsideClick: "false"
    openOnClick: "false"
    content: [
      html: "<div />"
      ref: "ComboBox_content"
    ,
      # Negative tabindex prevents tabstop, which isn't necessary here
      # as the text box portion will get the focus, and the user can
      # invoke the popup from there. E.g., ListComboBox opens the popup
      # when the Down key is pressed.
      # TODO: Promote Down key behavior from ListComboBox to this class.
      control: "ToggleButton"
      ref: "dropdownButton"
      class: "quiet"
      tabindex: "-1"
      content: "▼"
    ]
    generic: "true"

  # True if the dropdown portion should automatically close if the user
  # presses Enter. Default is true.
  closeOnEnter: Control.property.bool( null, true )

  # The content of the combo box's input portion.
  content: Control.chain( "$ComboBox_content", "content" )

  # The content of the dropdown button. By default, this shows a
  # downward-pointing arrow.
  dropdownButtonContent: Control.chain( "$dropdownButton", "content" )
  initialize: ->
    @$PopupSource_popup().on
      canceled: =>
        @$dropdownButton().selected false

      closed: =>
        # Closing the popup leaves the text selected.
        # HACK for IE: If we set focus to the input while the popup is
        # being closed, IE won't hide the popup. It seems quite hard
        # to prevent this behavior, so we simply disable the selection
        # behavior in IE.
        unless Control.browser.msie
          content = @content()
          @inputElement().focus()
          @_selectText 0, content.length
        @$dropdownButton().selected false
    
    # Close the popup when the control loses focus.
    @on
      focusout: ( event ) =>
        # We want to close the popup if the focus moves completely
        # outside the combo box; i.e., is not within the input box or
        # the popup. Unfortunately, if the user clicks in the popup,
        # the input will blur before we've had a chance to even
        # register the click. And at the point the blur handler here
        # is invoked, the new activeElement is not yet known, so we
        # can't test that.  
        # 
        # Our solution is to set a timeout which will defer testing
        # of activeElement until after the normal focusout sequence
        # has completed and focus has been placed in the new control.
        if @opened()
          setTimeout( =>
            focusInControl = $.contains( self[0], document.activeElement )
            # Still open?
            @cancel()  if not focusInControl and @opened()
          , 1 )
          return # Avoid implicitly returning timeout.

    @$dropdownButton().click ( event ) =>
      @open()

    
    # Allow the popup container itself to receive the focus.
    # This allows clicks on the popup to still keep focus within the
    # overall ComboBox controls.
    @$PopupSource_popup().prop "tabindex", -1
    
    # Set a default text box class
    @textBoxClass TextBox  unless @textBoxClass()

  # Returns the combo box's input element. By default this is the content
  # element itself (if it's a text box) or else the first text input element
  # in the content. Subclasses can override this to indicate that a different
  # element should be used for input.
  inputElement: ->
    $content = @$ComboBox_content()
    
    # Content itself is a text input element.
    return $content  if $content[0].nodeName.toLowerCase() is "input" and $content.prop( "type" ) is "text"
    
    # Return the first text input element.
    @$ComboBox_content().find( "input[type='text']" ).eq 0

  # Open the combo box.
  open: -><commit_msg>Fix dangling reference to "self".<commit_after>###
An input area with a dropdown arrow, which invokes a popup.
###

class window.ComboBox extends PopupSource

  inherited:
    closeOnInsideClick: "false"
    openOnClick: "false"
    content: [
      html: "<div />"
      ref: "ComboBox_content"
    ,
      # Negative tabindex prevents tabstop, which isn't necessary here
      # as the text box portion will get the focus, and the user can
      # invoke the popup from there. E.g., ListComboBox opens the popup
      # when the Down key is pressed.
      # TODO: Promote Down key behavior from ListComboBox to this class.
      control: "ToggleButton"
      ref: "dropdownButton"
      class: "quiet"
      tabindex: "-1"
      content: "▼"
    ]
    generic: "true"

  # True if the dropdown portion should automatically close if the user
  # presses Enter. Default is true.
  closeOnEnter: Control.property.bool( null, true )

  # The content of the combo box's input portion.
  content: Control.chain( "$ComboBox_content", "content" )

  # The content of the dropdown button. By default, this shows a
  # downward-pointing arrow.
  dropdownButtonContent: Control.chain( "$dropdownButton", "content" )
  initialize: ->
    @$PopupSource_popup().on
      canceled: =>
        @$dropdownButton().selected false

      closed: =>
        # Closing the popup leaves the text selected.
        # HACK for IE: If we set focus to the input while the popup is
        # being closed, IE won't hide the popup. It seems quite hard
        # to prevent this behavior, so we simply disable the selection
        # behavior in IE.
        unless Control.browser.msie
          content = @content()
          @inputElement().focus()
          @_selectText 0, content.length
        @$dropdownButton().selected false
    
    # # Close the popup when the control loses focus.
    @on
      focusout: ( event ) =>
        # We want to close the popup if the focus moves completely
        # outside the combo box; i.e., is not within the input box or
        # the popup. Unfortunately, if the user clicks in the popup,
        # the input will blur before we've had a chance to even
        # register the click. And at the point the blur handler here
        # is invoked, the new activeElement is not yet known, so we
        # can't test that.  
        # 
        # Our solution is to set a timeout which will defer testing
        # of activeElement until after the normal focusout sequence
        # has completed and focus has been placed in the new control.
        if @opened()
          setTimeout =>
            focusInControl = $.contains( @[0], document.activeElement )
            # Still open?
            if not focusInControl and @opened()
              @cancel()
          , 1

    @$dropdownButton().click ( event ) =>
      @open()
    
    # Allow the popup container itself to receive the focus.
    # This allows clicks on the popup to still keep focus within the
    # overall ComboBox controls.
    @$PopupSource_popup().prop "tabindex", -1
    
    # Set a default text box class
    @textBoxClass TextBox  unless @textBoxClass()

  # Returns the combo box's input element. By default this is the content
  # element itself (if it's a text box) or else the first text input element
  # in the content. Subclasses can override this to indicate that a different
  # element should be used for input.
  inputElement: ->
    $content = @$ComboBox_content()
    
    # Content itself is a text input element.
    return $content  if $content[0].nodeName.toLowerCase() is "input" and $content.prop( "type" ) is "text"
    
    # Return the first text input element.
    @$ComboBox_content().find( "input[type='text']" ).eq 0

  # Open the combo box.
  open: ->
{'fraction_non_alphanumeric': 0.08206686930091185, 'fraction_numerical': 0.0018501387604070306, 'mean_word_length': 2.498844197873324, 'pattern_counts': {'":': 0, '<': 5, '<?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': '1188906', 'n_tokens_mistral': 2084, 'n_tokens_neox': 1994, 'n_words': 891}