<commit_before><template lang="html">
  <div class="selectize-base">
    <b-input-group>
      <b-input-group-prepend is-text>
        <label class="sr-only" for="selectize">{{ ariaLabel }}</label>
        <icon :iname="searchIcon" v-if="searchIcon" />
      </b-input-group-prepend>
      <b-form-input
        id="selectize" :class="visible ? null : 'collapsed'"
        aria-controls="collapse" :aria-expanded="visible ? 'true' : 'false'"
        @focus="onInputFocus" @blur="onInputBlur" @keydown="onInputKeydown"
        v-model="search" ref="input"
      />
    </b-input-group>

    <b-collapse id="collapse" ref="collapse" v-model="visible">
      <b-list-group tabindex="-1" @mouseover="onChoiceListOver" v-if="visible">
        <b-list-group-item
          v-for="(item, index) in filteredChoices" :key="item"
          tabindex="-1" :active="index === focusedIndex" ref="choiceList"
          @mousedown.prevent @mouseup.prevent="onSelect(item)"
        >
          {{ item | filter(format) }}
        </b-list-group-item>
      </b-list-group>
    </b-collapse>
  </div>
</template>

<script>
// FIXME add accessibility to ChoiceList

export default {
  name: 'BaseSelectize',

  props: {
    choices: { type: Array, required: true },
    ariaLabel: { type: String, required: true },
    searchIcon: { type: String, default: 'search' },
    // FIXME find a better way to pass filters
    format: { type: Function, default: null }
  },

  data: () => ({
    visible: false,
    search: '',
    focusedIndex: 0
  }),

  computed: {
    filteredChoices () {
      const search = this.search.toLowerCase()
      return this.choices.filter(item => {
        return item.toLowerCase().includes(search)
      }).sort()
    }
  },

  methods: {
    onInputFocus ({ relatedTarget }) {
      this.visible = true
      this.focusedIndex = 0
      // timeout needed else scrollIntoView won't work
      if (!this.$refs.choiceList) return
      setTimeout(() => {
        this.$refs.choiceList[0].scrollIntoView({ behavior: 'instant', block: 'nearest', inline: 'nearest' })
      }, 50)
    },

    onInputBlur ({ relatedTarget }) {
      if (!this.$refs.collapse.$el.contains(relatedTarget)) {
        this.visible = false
      }
    },

    onInputKeydown (e) {
      const { key } = e
      const choicesLen = this.filteredChoices.length
      if (choicesLen < 1) return

      if (key === 'ArrowDown') {
        e.preventDefault()
        if (this.focusedIndex <= choicesLen) {
          this.focusedIndex++
        }
      } else if (key === 'ArrowUp') {
        e.preventDefault()
        if (this.focusedIndex > 0) {
          this.focusedIndex--
        }
      } else if (key === 'Enter') {
        this.onSelect(this.focusedIndex)
      } else {
        this.focusedIndex = 0
      }
      const elemToFocus = this.$refs.choiceList[this.focusedIndex]
      if (elemToFocus) {
        elemToFocus.scrollIntoView({ behavior: 'instant', block: 'nearest', inline: 'nearest' })
      }
    },

    onChoiceListOver ({ target }) {
      const index = this.$refs.choiceList.indexOf(target)
      if (index > -1) {
        this.focusedIndex = index
      }
    },

    onSelect (item) {
      this.$emit('selected', { item, index: this.choices.indexOf(item) })
      this.focusedIndex = 0
    }
  },

  filters: {
    filter: function (text, func) {<commit_msg>fixed selected event emition<commit_after><template lang="html">
  <div class="selectize-base">
    <b-input-group>
      <b-input-group-prepend is-text>
        <label class="sr-only" for="selectize">{{ ariaLabel }}</label>
        <icon :iname="searchIcon" v-if="searchIcon" />
      </b-input-group-prepend>
      <b-form-input
        id="selectize" :class="visible ? null : 'collapsed'"
        aria-controls="collapse" :aria-expanded="visible ? 'true' : 'false'"
        @focus="onInputFocus" @blur="onInputBlur" @keydown="onInputKeydown"
        v-model="search" ref="input"
      />
    </b-input-group>

    <b-collapse id="collapse" ref="collapse" v-model="visible">
      <b-list-group tabindex="-1" @mouseover="onChoiceListOver" v-if="visible">
        <b-list-group-item
          v-for="(item, index) in filteredChoices" :key="item"
          tabindex="-1" :active="index === focusedIndex" ref="choiceList"
          @mousedown.prevent @mouseup.prevent="onSelect(item)"
        >
          {{ item | filter(format) }}
        </b-list-group-item>
      </b-list-group>
    </b-collapse>
  </div>
</template>

<script>
// FIXME add accessibility to ChoiceList

export default {
  name: 'BaseSelectize',

  props: {
    choices: { type: Array, required: true },
    ariaLabel: { type: String, required: true },
    searchIcon: { type: String, default: 'search' },
    // FIXME find a better way to pass filters
    format: { type: Function, default: null }
  },

  data: () => ({
    visible: false,
    search: '',
    focusedIndex: 0
  }),

  computed: {
    filteredChoices () {
      const search = this.search.toLowerCase()
      return this.choices.filter(item => {
        return item.toLowerCase().includes(search)
      }).sort()
    }
  },

  methods: {
    onInputFocus ({ relatedTarget }) {
      this.visible = true
      this.focusedIndex = 0
      // timeout needed else scrollIntoView won't work
      if (!this.$refs.choiceList) return
      setTimeout(() => {
        this.$refs.choiceList[0].scrollIntoView({ behavior: 'instant', block: 'nearest', inline: 'nearest' })
      }, 50)
    },

    onInputBlur ({ relatedTarget }) {
      if (!this.$refs.collapse.$el.contains(relatedTarget)) {
        this.visible = false
      }
    },

    onInputKeydown (e) {
      const { key } = e
      const choicesLen = this.filteredChoices.length
      if (choicesLen < 1) return

      if (key === 'ArrowDown') {
        e.preventDefault()
        if (this.focusedIndex <= choicesLen) {
          this.focusedIndex++
        }
      } else if (key === 'ArrowUp') {
        e.preventDefault()
        if (this.focusedIndex > 0) {
          this.focusedIndex--
        }
      } else if (key === 'Enter') {
        this.onSelect(this.filteredChoices[this.focusedIndex])
        this.focusedIndex = 0
      } else {
        this.focusedIndex = 0
      }
      const elemToFocus = this.$refs.choiceList[this.focusedIndex]
      if (elemToFocus) {
        elemToFocus.scrollIntoView({ behavior: 'instant', block: 'nearest', inline: 'nearest' })
      }
    },

    onChoiceListOver ({ target }) {
      const index = this.$refs.choiceList.indexOf(target)
      if (index > -1) {
        this.focusedIndex = index
      }
    },

    onSelect (item) {
      this.$emit('selected', { item, index: this.choices.indexOf(item) })
    }
  },

  filters: {
    filter: function (text, func) {
{'fraction_non_alphanumeric': 0.15594974131559497, 'fraction_numerical': 0.003547671840354767, 'mean_word_length': 2.4154467440686522, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 51, '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': '5307467', 'n_tokens_mistral': 2167, 'n_tokens_neox': 2102, 'n_words': 435}