All files form.js

86.89% Statements 53/61
76.67% Branches 23/30
84.21% Functions 16/19
86.44% Lines 51/59
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148    4x       23x 23x           17x       68x       66x 66x     66x       13x   13x   2x 2x 3x     13x 13x               3x 1x 1x 2x 2x 2x         2x                 3x       1x       2x 2x 2x 2x                   1x   1x   1x               14x 14x 14x 14x       17x       70x         15x 9x     15x 2x 15x 2x   15x           1x 1x 1x 1x         1x   1x 1x            
import debug from 'debug'
 
var log = debug('ddf.form')
 
class Field {
  constructor(form, name) {
    this.form = form
    this.name = name
  }
 
  get multiple() {
    // i can't believe this thing always return true, even on non multiple selects
    // this.element.multiple === true
    return this.element.attributes.multiple && this.element.attributes.multiple.value === 'multiple'
  }
 
  get selector() {
    return '[name=' + this.form.prefix + this.name + ']'
  }
 
  get element() {
    var result = this.form.element.querySelector(this.selector)
    Iif (result.name === undefined) {
      throw 'element ' + this.name + ' not found in ' + this.form.element
    }
    return result
  }
 
  get value() {
    let value = this.element.value
 
    if (this.multiple) {
      // wait until es7.comphrensions reach stage 2
      value = []
      for (let option of this.element.querySelectorAll('[selected=selected]'))
        value.push(option.value)
    }
 
    if (this._valueInitial === undefined) this._valueInitial = value
    return value
  }
 
  get values() {
    return this.multiple ? this.value : [this.value]
  }
 
  set value(value) {
    if (this.multiple) {
      let options = this.element.querySelectorAll('option')
      for (let i=0; i < options.length; i++) {
        let option = options[i]
        Eif (value.indexOf(option.value) >= 0)
          option.setAttribute('selected', 'selected')
        else
          option.removeAttribute('selected')
      }
    } else {
      this.element.value = value
    }
  }
 
  valueReset() {
    this.element.value = this._valueInitial
  }
 
  get labelSelector() {
    return 'label[for=' + this.element.id + ']'
  }
 
  get labelElement() {
    return this.form.element.querySelector(this.labelSelector)
  }
 
  get containerElement() {
    let htmlElement = this.element
    while (htmlElement = htmlElement.parentNode)
      Eif (htmlElement.querySelector(this.labelSelector) != undefined)
        return htmlElement
  }
 
  hide() {
    this.required = this.element.required
    this.containerElement.classList.add('ddf-hide')
    this.element.required = false
  }
 
  show() {
    Iif (this.element.required)
      this.element.required = true
    this.containerElement.classList.remove('ddf-hide')
    // might have been set on rendering
    this.element.classList.remove('ddf-hide')
  }
}
 
class Form {
  // A Form matches the Form instance in Django, has a form htmlElement, a
  // prefix and rules.
  constructor(element, rules, prefix) {
    this.element = element
    this.rules = rules
    this.prefix = prefix
    this.fields = {}
  }
 
  set prefix(value) {
    this._prefix = value || ''
  }
 
  get prefix() {
    return this._prefix ? this._prefix + '-' : ''
  }
 
  field(name) {
    // Make it up if it doesn't exist
    if (this.fields[name] === undefined)
      this.fields[name] = new Field(this, name)
 
    // Compensate for dumb hydratation done from JSON dict
    if (this.fields[name].form === undefined)
      this.fields[name].form = this
    if (this.fields[name].name === undefined)
      this.fields[name].name = name
 
    return this.fields[name]
  }
 
  // Update the form on instanciation to start with a clean state.
  bind(formElement) {
    // compensate for dumb json hydratation
    Eif (formElement !== undefined) this.element = formElement
    let update = this.update.bind(this)
    this.element.addEventListener('input', update)
    this.element.addEventListener('change', update)
  }
 
  // Update the UI.
  update() {
    log('[Form] ', this, '.update()')
 
    for (var i=0; i<this.rules.length; i++) {
      this.rules[i].apply(this)
    }
  }
}
 
export { Field, Form }