openfoodfoundation/openfoodnetwork

View on GitHub
app/webpacker/controllers/toggle_control_controller.js

Summary

Maintainability
A
0 mins
Test Coverage
import { Controller } from "stimulus";

// Toggle state of a control based on a condition.
//
// 1. When an action occurs on an element,
// 2. The element's value is inspected, and
// 3. The related control(s) are changed state
//
export default class extends Controller {
  static targets = ["control", "content", "chevron"];
  static values = { selector: String, match: String };

  disableIfPresent(event) {
    const present = !!this.#inputValue(event.currentTarget); // Coerce value to boolean

    this.#toggleDisabled(present);
  }

  enableIfPresent(event) {
    const present = !!this.#inputValue(event.currentTarget); // Coerce value to boolean

    this.#toggleDisabled(!present);
  }

  // Display the "content" target if element has data-toggle-show="true"
  // (TODO: why not use the "control" target?)
  toggleDisplay(event) {
    const input = event.currentTarget;
    this.contentTargets.forEach((t) => {
      t.style.display = input.dataset.toggleShow === "true" ? "block" : "none";
    });
  }

  // Toggle element specified by data-control-toggle-selector-value="<css selector>"
  // (TODO: give a more general name)
  toggleAdvancedSettings(event) {
    if (this.hasChevronTarget) {
      this.chevronTarget.classList.toggle("icon-chevron-down");
      this.chevronTarget.classList.toggle("icon-chevron-up");
    }

    const element = document.querySelector(this.selectorValue);
    element.style.display = element.style.display === "none" ? "block" : "none";
  }

  // Display the control if selected value matches value in data-toggle-match="<value>"
  displayIfMatch(event) {
    const inputValue = this.#inputValue(event.currentTarget);

    this.#toggleDisplay(inputValue == this.matchValue);
  }

  // private

  #toggleDisabled(disable) {
    this.controlTargets.forEach((target) => {
      target.disabled = disable;
    });

    // Focus first when enabled
    if (!disable) {
      this.controlTargets[0].focus();
    }
  }

  #toggleDisplay(show) {
    this.controlTargets.forEach((target) => {
      target.style.display = (show ? "block" : "none");
    });

    // Focus first when displayed
    if (show) {
      this.controlTargets[0].focus();
    }
  }

  // Return input's value, but only if it would be submitted by a form
  // Radio buttons not supported (yet)
  #inputValue(input) {
    if (input.type != "checkbox" || input.checked) {
      return input.value;
    }
  }
}