zorin-e
5/15/2018 - 7:13 AM

Mobile menu

Mobile version of the main menu

import {toggleButton} from 'utils'

class Menu {
	constructor() {
		// default nodes
		this._container = document.querySelector('.js-menu')
		this._container.btn = this._container.querySelector('.js-menu-btn')
		this._container.toggle = this._container.querySelector('.js-menu-toggle')
		this._container.contents = this._container.querySelector('.js-menu-contents')
		this._container.output = this._container.querySelector('.js-menu-output')
		this._container.elTitle = this._container.querySelector('.js-menu-title')
		this._container.textTitle = this._container.elTitle.textContent
		this._container.btnClose = this._container.querySelector('.js-menu-close')

		// default options
		this._options = {
			animation: false
		}
	}

	get container() {
		return this._container
	}

	set container(el) {
		this._container = el
	}

	get options() {
		return this._options
	}

	set options(props) {
		this._options = Object.assign({}, this._options, props)
	}

	// init user options
	init() {
		if(this.options.animation) {
			this.container.output.style.transition = 'left .4s cubic-bezier(.25, .8, .25, 1)'
			this.container.toggle.style.transition = 'top .8s cubic-bezier(.25, .8, .25, 1)'
		}
	}

	toggle({el, target, className}, add = true) {
		if(!this.container || !target) return

		el.classList.add(className)
		target.classList.remove(className)

		let percent = 100
		percent = percent * Array.prototype.indexOf.call(this.container.output.children, target)
		this.container.output.style.left = '-'+ percent +'%'

		// hide prev menu after animation
		el.classList.add(className)

		// map menu
		if(add) {
			if(!this.container.prevMenu) this.container.prevMenu = []
			
			this.container.prevMenu.push({
				el: el,
				target: target
			})

			// change title
			this._changeTitle(el)
		}
		else {
			// change title on default
			this._changeTitle(target, true)
		}

		// prev btn
		if(!this.container.btnPrev) this._defineBtnPrev({el, target, className})

		this.toggleBtnPrev(this.container.prevMenu.slice(-1).pop().el)
		
	}

	_changeTitle(el, prev = false) {
		if(!el.previousElementSibling && prev) {
			this.container.elTitle.innerHTML = this.container.textTitle
			return
		}

		const icon = el.querySelector('.js-menu-icon').cloneNode()
		let text =  prev ? this.container.prevMenu[this.container.prevMenu.length - 2].el.querySelector('.js-menu-text'): el.querySelector('.js-menu-text')
		icon.classList.remove('menu__icon')
		this.container.elTitle.innerHTML = icon.outerHTML + text.textContent
	}

	_defineBtnPrev(props) {
		this.container.btnPrev = this.container.querySelector('.js-menu-prev')

		// add anim to prev btn if animation true
		if(this.options.animation) this.container.btnPrev.style.transition = 'left .2s linear'

		// prev to menu
		this.container.btnPrev.addEventListener('click', e => {
			const lastMenu = this.container.prevMenu.slice(-1).pop()

			this.toggle({
				el: lastMenu.target,
				target: lastMenu.el,
				className: props.className
			}, false)

			this.toggleBtnPrev(lastMenu.target)

			// remove last menu
			this.container.prevMenu.pop()
		})
	}

	toggleBtnPrev(el) {
		if(!el.previousElementSibling) {
			this.container.btnPrev.classList.toggle('menu__prev--hidden')
		}
	}
}

export default new Menu()
import Menu from 'Menu'
import {toggleButton} from 'utils'

document.addEventListener('DOMContentLoaded', () => {
	/*============================
	=            Menu            =
	============================*/
	Menu.options = {
		animation: true
	}

	Menu.init()

	// open menu
	Menu.container.btn.addEventListener('click', e => {
		toggleButton({
			current: e.target,
			target: Menu.container.toggle,
			targetClassName: 'menu__wrapper--hidden'
		})
	})

	// close menu
	Menu.container.btnClose.addEventListener('click', e => {
		toggleButton({
			current: e.target,
			target: Menu.container.toggle,
			targetClassName: 'menu__wrapper--hidden'
		})
	})

	Menu.container.toggle.addEventListener('click', e => {
		if(!e.target.classList.contains('js-menu-toggle')) return

		toggleButton({
			current: e.target,
			target: Menu.container.toggle,
			targetClassName: 'menu__wrapper--hidden'
		})
	})

	Menu.container.toggle.addEventListener('click', e => {
		const el = e.target.classList.contains('js-show-child-menu') ? e.target : e.target.closest('.js-show-child-menu')
		if(!el) return

		Menu.toggle({
			el: el.closest('.js-menu-content'),
			target: Menu.container.toggle.querySelector('[data-child="'+ el.getAttribute('data-context') +'"]'),
			className: 'menu__content--hidden'
		})
	})
	/*=====  End of Menu  ======*/
});
/**
 *
 * @param {object} els (current, target, className)
 * @param {function} callback
 *
 */
export const toggleButton = (els, callback) => {
	if(els.className) els.current.classList.toggle(els.className);
	els.target.classList.toggle(els.targetClassName ? els.targetClassName : 'hidden');

	if(typeof callback === 'function') {
		callback()
	}
}