Source: scripts/utilities/_toggle.js

/**
 * @file
 * Toggle object.
 */

/**
 * @namespace toggle
 * @memberof UCASUtilities
 * @param {object} _u - UCASUtilities object.
 */
(function (_u) {
  var toggles = []
  // Wrapper with a fallback to document.
  // Wrapper is needed for the click event on iOS.
  var wrapper = document.querySelector('.page-wrapper') || document

  /**
   * A toggle object is returned from UCASUtilities.toggle.create().
   * @class
   * @memberof! UCASUtilities.toggle
   * @public
   * @example
   * toggleRef = UCASUtilities.toggle.create('my-id', function(){console.log('show')}, function(){console.log('hide')}, true)
   * toggleRef.show()
   * toggleRef.hide()
   */
  var Toggle = {
    init: function (id, showCallback, hideCallback, hideOnClickAway) {
      this.id = id
      this.showCallback = showCallback
      this.hideCallback = hideCallback
      this.$element = document.getElementById(id)

      this.show = function show () {
        if (typeof this.showCallback === 'function') {
          // If the callback returns false, exit early.
          if (this.showCallback() === false) {
            return
          }
        }
        if (hideOnClickAway) {
          wrapper.addEventListener('click', this, false)
        }
        this.$element.setAttribute('data-toggle-state', 'open')
      }.bind(this)

      this.hide = function hide () {
        if (typeof this.hideCallback === 'function') {
          // If the callback returns false, exit early.
          if (this.hideCallback() === false) {
            return
          }
        }
        wrapper.removeEventListener('click', this, false)
        this.$element.setAttribute('data-toggle-state', 'closed')
      }.bind(this)

      this.handleEvent = function (event) {
        event.stopPropagation()
        if (this.$element === event.target || this.$element.contains(event.target)) {
          event.preventDefault() // Prevent default on the actual toggle and its children only.
        }

        switch (event.type) {
          case 'click':
            this.$element.getAttribute('data-toggle-state') === 'open' ? this.hide() : this.show()
            break
        }
      }.bind(this)

      addEventListeners(this)
    },
    destroy: function () {
      removeEventListeners(this)
      delete toggles[this.id]
    }
  }

  /**
   * @param {Toggle} toggle - Toggle instance
   */
  function addEventListeners (toggle) {
    removeEventListeners(toggle)
    toggle.$element.addEventListener('click', toggle, true)
  }

  /**
   * @param {Toggle} toggle - Toggle instance
   */
  function removeEventListeners (toggle) {
    toggle.$element.removeEventListener('click', toggle, true)
    document.removeEventListener('click', toggle, false)
  }

  /**
   * @function hideOthers
   * @memberof! UCASUtilities.toggle
   * @param {string} id - the unique ID of the toggle element
   * @param {node} [context=document] - the ancestor node containing the toggle
   * @example
   * UCASUtilities.toggle.hideOthers('my-id')
   */
  function hideOthers (id, context) {
    context = context || document
    var open = context.querySelectorAll('[data-toggle-state="open"]')
    _u.forEach(open, function (i, el) {
      if (el.id && el.id !== id) {
        toggles[el.id].hide()
      }
    })
  }

  /**
   * Creates and registers a toggle, which is used to show or hide elements.
   * A toggle requires two callbacks: one for the show event and one for the hide event.
   * @function create
   * @memberof! UCASUtilities.toggle
   * @param {string} id - the unique ID of the toggle element
   * @param {function} show - a callback on show
   * @param {function} hide - a callback on hide
   * @param {boolean} hideOnClickAway - trigger hide when clicking away from the toggle
   * @return {Toggle} - a reference to the Toggle
   * @example
   * UCASUtilities.toggle.create('my-id', function(){console.log('show')}, function(){console.log('hide')}, true)
   */
  function create (id, show, hide, hideOnClickAway) {
    if (document.getElementById(id)) {
      toggles[id] = Object.create(Toggle)
      toggles[id].init(id, show, hide, hideOnClickAway)
      return toggles[id]
    } else {
      _u.log.log('No toggle with id ' + id)
    }
  }

  /**
   * @function destroy
   * @memberof! UCASUtilities.toggle
   * @param {string} id - the unique ID of the toggle element
   * @example
   * UCASUtilities.toggle.destroy('my-id')
   */
  function destroy (id) {
    if (toggles[id]) {
      toggles[id].destroy()
    } else {
      _u.log.log('No toggle with id ' + id)
    }
  }

  /**
   * @function hide
   * @memberof! UCASUtilities.toggle
   * @param {string} id - the unique ID of the toggle element
   * @example
   * UCASUtilities.toggle.hide('my-id')
   */
  function hideToggle (id) {
    if (toggles[id]) {
      toggles[id].hide()
    } else {
      _u.log.log('No toggle with id ' + id)
    }
  }

  /**
   * @function show
   * @memberof! UCASUtilities.toggle
   * @param {string} id - the unique ID of the toggle element
   * @example
   * UCASUtilities.toggle.show('my-id')
   */
  function showToggle (id) {
    if (toggles[id]) {
      toggles[id].show()
    } else {
      _u.log.log('No toggle with id ' + id)
    }
  }

  _u.toggle = {
    create: create,
    destroy: destroy,
    hideOthers: hideOthers,
    hide: hideToggle,
    show: showToggle
  }
}(UCASUtilities))