index/index.js

Summary

Maintainability
A
0 mins
Test Coverage
export class Filterform {
  /**
   * @member {function}
   */
  #tagSelector

  /**
   * @member {object}
   */
  #langs

  /**
   * @member {string}
   */
  #formSelector

  /**
   *
   * @param {string} formSelector
   * @param {function} tagSelector
   * @param {string[]} checkedLangs The array of initially-checked inputs.
   * @param {object} supportedLangs Key-values of languages
   * @param {function} tagAttribute returns the attribute that will provide a possible value to check.
   */
  constructor (formSelector, tagSelector, checkedLangs, supportedLangs, tagAttribute) {
    this.#formSelector = formSelector
    this.#tagSelector = tagSelector
    this.checked = checkedLangs
    this.#langs = supportedLangs
    this.tagAttribute = tagAttribute
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', ready)
    } else {
      this.ready()
    }
  }

  /**
   *
   * @param {string} value
   * @return {HTMLElement[]}
   */
  getTags (value) {
    const selector = this.#tagSelector(value)
    const tags = Array.from(document.querySelectorAll(selector))
      .filter(element => !['HTML', 'I'].includes(element.nodeName))
    const lang = this.#langs[value]
    return lang ? tags.map(tag => {
      const transform = lang.transform
      return transform ? transform(tag) : tag
    }) : tags
  }

  clicked () {
    const inputs = Array.from(document.querySelectorAll(this.#formSelector + ` input[type="checkbox"]`))
    for (const input of inputs) {
      const tags = this.getTags(input.value)
      for (let i = 0; i < tags.length; i++) {
        const item = tags[i]
        item.classList.toggle('visible', input.checked)
        item.classList.toggle('hidden', !input.checked)
        this.hint(input, input.checked ? 'Cliquez pour masquer' : 'Cliquez pour afficher')
        const id = item.getAttribute('id')
        if (id) {
          item.setAttribute('value', id)
        }
      }
    }
    const checkedOnes = inputs.filter(input => input.checked)
    if (checkedOnes.length <= 1) {
      checkedOnes.forEach(checkedOne => {
        checkedOne.disabled = true
        let listStyleType
        let dir
        switch (checkedOne.value) {
          case 'he':
            listStyleType = 'hebrew'
            dir = 'rtl'
            break
          case 'ar':
            listStyleType = 'arabic-indic'
            dir = 'rtl'
            break
          default:
            listStyleType = null
            dir = null
        }
        const list = document.querySelector('ol.indexed')
        if (list) {
          list.style['list-style-type'] = listStyleType
          list.setAttribute('dir', dir)
        }
        this.hint(checkedOne, inputs.length > 1 ? 'Sélectionnez un autre choix avant de déselectionner celui-ci' : 'Seul choix disponible')
      })
    } else {
      checkedOnes.forEach(checkedOne => {
        checkedOne.disabled = false
      })
    }
  }

  hint (input, hint) {
    const labeled = input.parentElement.nodeName === 'LABEL' ? input.parentElement : input
    labeled.title = hint
  }

  ready () {
    const ps = this.getTags()
    const values = ps.reduce((ls, p) => {
      ls.add(this.tagAttribute(p))
      return ls
    }, new Set())
    const valuesArr = Array.from(values)
    let checked = valuesArr.filter(value => this.checked.includes(value))
    if (checked.length <= 0) {
      checked = valuesArr[0]
    }
    const form = document.querySelector(this.#formSelector)
    for (const value of values) {
      const label = document.createElement('label')
      const input = document.createElement('input')
      input.type = 'checkbox'
      input.value = value
      input.onclick = this.clicked.bind(this)
      if (checked.includes(value)) {
        input.checked = true
      }
      label.appendChild(input)
      const lang = this.#langs[value]
      if (lang) {
        label.append(' ' + lang.label)
        form.append(label)
      } else {
        console.warn('Unusupported lang', lang)
      }
    }
    this.clicked()
  }
}