View file Maxton/maxton/assets/plugins/bs-stepper/js/index.js

File size: 3.28Kb
import { show, customProperty, detectAnimation, ClassName } from './util'
import { buildClickStepLinearListener, buildClickStepNonLinearListener } from './listeners'

const DEFAULT_OPTIONS = {
  linear: true,
  animation: false,
  selectors: {
    steps: '.step',
    trigger: '.step-trigger',
    stepper: '.bs-stepper'
  }
}

class Stepper {
  constructor (element, _options = {}) {
    this._element = element
    this._currentIndex = 0
    this._stepsContents = []

    this.options = {
      ...DEFAULT_OPTIONS,
      ..._options
    }

    this.options.selectors = {
      ...DEFAULT_OPTIONS.selectors,
      ...this.options.selectors
    }

    if (this.options.linear) {
      this._element.classList.add(ClassName.LINEAR)
    }

    this._steps = [].slice.call(this._element.querySelectorAll(this.options.selectors.steps))

    this._steps.filter(step => step.hasAttribute('data-target'))
      .forEach(step => {
        this._stepsContents.push(
          this._element.querySelector(step.getAttribute('data-target'))
        )
      })

    detectAnimation(this._stepsContents, this.options)
    this._setLinkListeners()
    Object.defineProperty(this._element, customProperty, {
      value: this,
      writable: true
    })

    if (this._steps.length) {
      show(this._element, this._currentIndex, this.options, () => {})
    }
  }

  // Private

  _setLinkListeners () {
    this._steps.forEach(step => {
      const trigger = step.querySelector(this.options.selectors.trigger)

      if (this.options.linear) {
        this._clickStepLinearListener = buildClickStepLinearListener(this.options)
        trigger.addEventListener('click', this._clickStepLinearListener)
      } else {
        this._clickStepNonLinearListener = buildClickStepNonLinearListener(this.options)
        trigger.addEventListener('click', this._clickStepNonLinearListener)
      }
    })
  }

  // Public

  next () {
    const nextStep = (this._currentIndex + 1) <= this._steps.length - 1 ? this._currentIndex + 1 : (this._steps.length - 1)

    show(this._element, nextStep, this.options, () => {
      this._currentIndex = nextStep
    })
  }

  previous () {
    const previousStep = (this._currentIndex - 1) >= 0 ? this._currentIndex - 1 : 0

    show(this._element, previousStep, this.options, () => {
      this._currentIndex = previousStep
    })
  }

  to (stepNumber) {
    const tempIndex = stepNumber - 1
    const nextStep = tempIndex >= 0 && tempIndex < this._steps.length
      ? tempIndex
      : 0

    show(this._element, nextStep, this.options, () => {
      this._currentIndex = nextStep
    })
  }

  reset () {
    show(this._element, 0, this.options, () => {
      this._currentIndex = 0
    })
  }

  destroy () {
    this._steps.forEach(step => {
      const trigger = step.querySelector(this.options.selectors.trigger)

      if (this.options.linear) {
        trigger.removeEventListener('click', this._clickStepLinearListener)
      } else {
        trigger.removeEventListener('click', this._clickStepNonLinearListener)
      }
    })

    this._element[customProperty] = undefined
    this._element = undefined
    this._currentIndex = undefined
    this._steps = undefined
    this._stepsContents = undefined
    this._clickStepLinearListener = undefined
    this._clickStepNonLinearListener = undefined
  }
}

export default Stepper