All files / app/assets/javascripts/dirty_submit dirty_submit_form.js

86.67% Statements 39/45
81.25% Branches 13/16
86.67% Functions 13/15
90% Lines 36/40

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          17x 17x 17x   17x       23x 23x   23x 23x   23x       23x 27x     23x 36x 36x     23x 23x 23x 23x       27x   27x   27x 27x       27x   27x 27x 27x   27x 27x       50x 50x 39x                           200x 200x       227x       227x       4x      
import $ from 'jquery';
import { memoize, throttle } from 'lodash';
 
class DirtySubmitForm {
  constructor(form) {
    this.form = form;
    this.dirtyInputs = [];
    this.isDisabled = true;
 
    this.init();
  }
 
  init() {
    this.inputs = this.form.querySelectorAll('input, textarea, select');
    this.submits = this.form.querySelectorAll('input[type=submit], button[type=submit]');
 
    this.inputs.forEach(DirtySubmitForm.initInput);
    this.toggleSubmission();
 
    this.registerListeners();
  }
 
  registerListeners() {
    const getThrottledHandlerForInput = memoize(() =>
      throttle((event) => this.updateDirtyInput(event), DirtySubmitForm.THROTTLE_DURATION),
    );
 
    const throttledUpdateDirtyInput = (event) => {
      const throttledHandler = getThrottledHandlerForInput(event.target.name);
      throttledHandler(event);
    };
 
    this.form.addEventListener('input', throttledUpdateDirtyInput);
    this.form.addEventListener('change', throttledUpdateDirtyInput);
    $(this.form).on('change.select2', throttledUpdateDirtyInput);
    this.form.addEventListener('submit', (event) => this.formSubmit(event));
  }
 
  updateDirtyInput(event) {
    const { target } = event;
 
    Iif (!target.dataset.isDirtySubmitInput) return;
 
    this.updateDirtyInputs(target);
    this.toggleSubmission();
  }
 
  updateDirtyInputs(input) {
    const { name } = input;
    const isDirty =
      input.dataset.dirtySubmitOriginalValue !== DirtySubmitForm.inputCurrentValue(input);
    const indexOfInputName = this.dirtyInputs.indexOf(name);
    const isExisting = indexOfInputName !== -1;
 
    if (isDirty && !isExisting) this.dirtyInputs.push(name);
    if (!isDirty && isExisting) this.dirtyInputs.splice(indexOfInputName, 1);
  }
 
  toggleSubmission() {
    this.isDisabled = this.dirtyInputs.length === 0;
    this.submits.forEach((element) => {
      element.disabled = this.isDisabled;
    });
  }
 
  formSubmit(event) {
    if (this.isDisabled) {
      event.preventDefault();
      event.stopImmediatePropagation();
    }
 
    return !this.isDisabled;
  }
 
  static initInput(element) {
    element.dataset.isDirtySubmitInput = true;
    element.dataset.dirtySubmitOriginalValue = DirtySubmitForm.inputCurrentValue(element);
  }
 
  static isInputCheckable(input) {
    return input.type === 'checkbox' || input.type === 'radio';
  }
 
  static inputCurrentValue(input) {
    return DirtySubmitForm.isInputCheckable(input) ? input.checked.toString() : input.value;
  }
}
 
DirtySubmitForm.THROTTLE_DURATION = 500;
 
export default DirtySubmitForm;