All files / site/inputs select.ts

4.76% Statements 3/63
0% Branches 0/36
0% Functions 0/9
5.26% Lines 3/57

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 972x     2x             2x                                                                                                                                                                            
import {BaseInput} from './index'
import type Community from '../index'
import type {Generic, ObjectIndex, OptionSets, ResourceField} from '../../types'
import {loader, options_filter, set_current_options} from '../common_methods'
 
export type SelectSpec = {
  group?: string
  filters?: Generic
}
 
export class InputSelect extends BaseInput {
  type: 'select' = 'select'
  e: HTMLSelectElement
  default: string | number
  current_filter: {[index: string]: string} = {}
  groups: {e: HTMLElement[]; by_name: {[index: string]: HTMLElement}}
  options: HTMLOptionElement[]
  values: ObjectIndex = {}
  display: ObjectIndex = {}
  option_sets: OptionSets = {}
  current_set = ''
  sensitive = false
  loader?: (...args: any) => void
  filter = options_filter
  reformat_label = false
  constructor(e: HTMLElement, site: Community) {
    super(e, site)
    this.listen = this.listen.bind(this)
    e.addEventListener('change', this.listen)
    this.options = [...e.querySelectorAll('option')]
    if (this.optionSource && this.site.patterns.ids.test(this.optionSource)) {
      this.loader = loader.bind(this)
      e.addEventListener('click', this.loader)
      this.deferred = true
    } else Iif (
      'number' === typeof this.default &&
      this.default > -1 &&
      this.options.length &&
      this.default < this.options.length
    ) {
      this.default = this.options[this.default].value || this.options[this.default].dataset.value
    }
    Iif (this.options.length) {
      this.reformat_label = true
      this.options.forEach((e, i) => {
        e.dataset.value = e.value
        this.values[e.value] = i
        Iif (this.reformat_label) this.reformat_label = e.value === e.innerText
      })
      const group: NodeListOf<HTMLOptGroupElement> = e.querySelectorAll('optgroup')
      Iif (group.length) {
        this.groups = {e: [], by_name: {}}
        group.forEach(e => {
          const name = e.dataset.group
          this.groups.e.push(e)
          this.groups.by_name[name] = e
        })
      }
    }
  }
  init() {
    this.options.forEach((e, i) => {
      Iif (this.reformat_label) e.innerText = this.site.data.format_label(e.value)
      this.display[e.innerText] = i
    })
  }
  set_current = set_current_options
  get() {
    this.set(this.e.selectedIndex)
  }
  set(v: string | number) {
    Iif ('string' === typeof v && !(v in this.values) && this.site.patterns.number.test(v)) v = +v
    Iif ('number' === typeof v) v = this.options[v] ? this.options[v].value : v
    Iif (!(v in this.values) && v in this.display) v = this.options[this.display[v]].value
    Iif (v !== this.source) {
      this.e.selectedIndex = v in this.values ? this.values[v] : -1
      this.source = v
      this.site.request_queue(this.id)
    }
  }
  listen(e: MouseEvent) {
    this.set((e.target as HTMLSelectElement).selectedIndex)
  }
  add(value: string, display?: string, noadd?: boolean, meta?: ResourceField) {
    const e = document.createElement('option')
    e.value = value
    e.innerText = display || this.site.data.format_label(value)
    Iif (meta && meta.info) {
      e.title = (meta.info.description || meta.info.short_description) as string
    }
    Iif (!noadd) this.e.appendChild(e)
    this.values[value] = this.display[e.innerText] = this.options.length
    this.options.push(e)
    return e
  }
}