/** * Navigation component. * * @author Htmlstream * @version 1.0 * @requires HSScrollBar component (hs.scrollbar.js v1.0.0) * */ ;(function ($) { 'use strict'; $.HSCore.components.HSNavigation = { /** * Base configuration of the component. * * @private */ _baseConfig: { navigationOverlayClasses: '', navigationInitClasses: '', navigationInitBodyClasses: '', navigationPosition: 'right', activeClass: 'u-main-nav--overlay-opened', navigationBreakpoint: 768, breakpointsMap: { 'sm': 576, 'md': 768, 'lg': 992, 'xl': 1200 }, afterOpen: function(){}, afterClose: function(){} }, /** * Collection of all initialized items on the page. * * @private */ _pageCollection: $(), /** * Initializtion of the navigation. * * @param {jQuery} collection * @param {Object} config * * @public * @return {jQuery} */ init: function( collection, config ) { var _self = this, $w = $(window); if(!collection || !collection.length) return $(); config = config && $.isPlainObject(config) ? config : {}; $w.on('resize.HSNavigation', function(e){ if(_self.resizeTimeoutId) clearTimeout(_self.resizeTimeoutId); _self.resizeTimeoutId = setTimeout(function(){ _self._pageCollection.each(function(i, el){ var $this = $(el), HSNavigation = $this.data('HSNavigation'); if($w.width() > HSNavigation.config.breakpointsMap[HSNavigation.config.navigationBreakpoint] && HSNavigation.isInitialized() ) { HSNavigation.destroy(); } else if($w.width() <= HSNavigation.config.breakpointsMap[HSNavigation.config.navigationBreakpoint] && !HSNavigation.isInitialized()) { HSNavigation.init(); } }); }, 50); }); collection.each(function(i, el){ var $this = $(el), itemConfig = $.extend(true, {}, _self._baseConfig, config, $this.data()); if( $this.data('HSNavigation') ) return; $this.data('HSNavigation', _self._factoryMethod( $this, itemConfig )); _self._pageCollection = _self._pageCollection.add( $this ); }); _self._pageCollection.each(function(i, el){ var $this = $(el), HSNavigation = $this.data('HSNavigation'); if($w.width() > HSNavigation.config.breakpointsMap[HSNavigation.config.navigationBreakpoint] ) { HSNavigation.destroy(); } else if($w.width() <= HSNavigation.config.breakpointsMap[HSNavigation.config.navigationBreakpoint] ) { HSNavigation.init(); } }); return collection; }, /** * Returns certain object relative to class name. * * @param {jQuery} element * @param {Object} config * * @private * @return {HSNavigationOverlay|HSNavigationPush} */ _factoryMethod: function(element, config) { if( element.filter('[class*="u-main-nav--overlay"]').length ) { return new HSNavigationOverlay(element, config); } else if ( element.filter('[class*="u-main-nav--push"]').length ) { return new HSNavigationPush(element, config); } } }; /** * Abstract class for all HSNavigation* objects. * * @param {jQuery} element * @param {Object} config * * @return {Boolean} */ function HSNavigationAbstract(element, config) { /** * Contains current jQuery object. * * @public */ this.element = element; /** * Contains body jQuery object. * * @public */ this.body = $('body'); /** * Contains configuration. * * @public */ this.config = config; /** * Reinitialization of the HSNavigation* object. * * @public */ this.reinit = function() { this.destroy().init(); } }; /** * HSNavigationOverlay. * * @param {jQuery} element * @param {Object} config * * @constructor */ function HSNavigationOverlay(element, config) { var _self = this; // extends some functionality from abstract class HSNavigationAbstract.call(this, element, config); Object.defineProperties(this, { overlayClasses: { get: function() { return 'u-main-nav__overlay ' + _self.config.navigationOverlayClasses } }, bodyClasses: { get: function() { return 'u-main-nav--overlay-' + _self.config.navigationPosition } }, isOpened: { get: function() { return _self.body.hasClass( _self.config.activeClass ); } } }); }; /** * Initialization of the instance. * * @public */ HSNavigationOverlay.prototype.init = function() { var _self = this; /** * Contains overlay object. * * @public */ this.overlay = $('
', { class: _self.overlayClasses }); if( $.HSCore.components.HSScrollBar ) { setTimeout(function(){ $.HSCore.components.HSScrollBar.init( _self.element.find( '.u-main-nav__list-wrapper' ) ); }, 10); } this.toggler = $('[data-target="#'+ this.element.attr('id') +'"]'); if(this.toggler && this.toggler.length) this.toggler.css('display', 'block'); this.body.addClass( this.bodyClasses ); this.element .addClass('u-main-nav--overlay') .append(this.overlay); setTimeout(function(){ _self.element.addClass( _self.config.navigationInitClasses ); _self.body.addClass( _self.config.navigationInitBodyClasses ); _self.transitionDuration = parseFloat( getComputedStyle(_self.element.get(0)).transitionDuration, 10 ); if(_self.transitionDuration > 0) { _self.element.on("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend", function(e){ if(_self.isOpened && (e.originalEvent.propertyName == 'right' || e.originalEvent.propertyName == 'left')) { _self.config.afterOpen.call(_self.element, _self.overlay); } else if(!_self.isOpened && (e.originalEvent.propertyName == 'right' || e.originalEvent.propertyName == 'left')) { _self.config.afterClose.call(_self.element, _self.overlay); } e.stopPropagation(); e.preventDefault(); }); } },50); this._bindEvents(); this.isInit = true; }; /** * Destroys the instance. * * @public */ HSNavigationOverlay.prototype.destroy = function() { var _self = this; if(this.overlay) this.overlay.remove(); if(this.toggler && this.toggler.length) this.toggler.hide(); if( $.HSCore.components.HSScrollBar ) { setTimeout(function(){ $.HSCore.components.HSScrollBar.destroy( _self.element.find( '.u-main-nav__list-wrapper' ) ); }, 10); } setTimeout(function(){ if(_self.transitionDuration && _self.transitionDuration > 0) { _self.element.off("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend"); } },50); this.body.removeClass( this.bodyClasses ); this.element .removeClass('u-main-nav--overlay') .removeClass(this.config.navigationInitClasses); this.body.removeClass( this.bodyClasses ).removeClass(this.config.navigationInitBodyClasses); this._unbindEvents(); this.isInit = false; }; /** * Binds necessary events. * * @private */ HSNavigationOverlay.prototype._bindEvents = function() { var _self = this; if(this.toggler && this.toggler.length) { this.toggler.on('click.HSNavigation', function(e){ if(_self.isOpened) { _self.close(); } else { _self.open(); } e.preventDefault(); }); } this.overlay.on('click.HSNavigation', function(e){ _self.close(); }); $(document).on('keyup.HSNavigation', function(e){ if(e.keyCode == 27) { _self.close(); } }); }; /** * Unbinds necessary events. * * @private */ HSNavigationOverlay.prototype._unbindEvents = function() { if(this.toggler && this.toggler.length) { this.toggler.off('click.HSNavigation'); } if(this.overlay && this.overlay.length) { this.overlay.off('click.HSNavigation'); } $(document).off('keyup.HSNavigation'); }; /** * Shows the navigation. * * @public */ HSNavigationOverlay.prototype.open = function() { this.body.addClass( this.config.activeClass ); if(this.transitionDuration !== undefined && this.transitionDuration == 0) { this.config.afterOpen.call(this.element, this.overlay); } }; /** * Hides the navigation. * * @public */ HSNavigationOverlay.prototype.close = function() { var hamburgers = this.toggler && this.toggler.length ? this.toggler.find('.is-active') : $(); if(hamburgers.length) hamburgers.removeClass('is-active'); this.body.removeClass( this.config.activeClass ); if(this.transitionDuration !== undefined && this.transitionDuration == 0) { this.config.afterClose.call(this.element, this.overlay); } }; /** * Returns true if the navigation has been initialized. * * @public * @return {Boolean} */ HSNavigationOverlay.prototype.isInitialized = function() { return this.isInit; }; /** * HSNavigationPush. * * @param {jQuery} element * @param {Object} config * * @constructor */ function HSNavigationPush(element, config) { var _self = this; // extends some functionality from abstract class HSNavigationAbstract.call(this, element, config); Object.defineProperties(this, { overlayClasses: { get: function() { return 'u-main-nav__overlay ' + _self.config.navigationOverlayClasses } }, bodyClasses: { get: function() { return 'u-main-nav--push-' + _self.config.navigationPosition } }, isOpened: { get: function() { return _self.body.hasClass( _self.config.activeClass ); } } }); // this.init(); }; /** * Initialization of the instance. * * @public */ HSNavigationPush.prototype.init = function() { var _self = this; /** * Contains overlay object. * * @public */ this.overlay = $('
', { class: _self.overlayClasses }); if( $.HSCore.components.HSScrollBar ) { setTimeout(function(){ $.HSCore.components.HSScrollBar.init( _self.element.find( '.u-main-nav__list-wrapper' ) ); }, 10); } this.toggler = $('[data-target="#'+ this.element.attr('id') +'"]'); if(this.toggler && this.toggler.length) this.toggler.css('display', 'block'); this.body.addClass( this.bodyClasses ); this.element .addClass('u-main-nav--push') .append(this.overlay); setTimeout(function(){ _self.element.addClass( _self.config.navigationInitClasses ); _self.body.addClass( _self.config.navigationInitBodyClasses ); _self.transitionDuration = parseFloat( getComputedStyle(_self.element.get(0)).transitionDuration, 10 ); if(_self.transitionDuration > 0) { _self.element.on("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend", function(e){ if(_self.isOpened && (e.originalEvent.propertyName == 'right' || e.originalEvent.propertyName == 'left')) { _self.config.afterOpen.call(_self.element, _self.overlay); } else if(!_self.isOpened && (e.originalEvent.propertyName == 'right' || e.originalEvent.propertyName == 'left')) { _self.config.afterClose.call(_self.element, _self.overlay); } e.stopPropagation(); e.preventDefault(); }); } },50); this._bindEvents(); this.isInit = true; }; /** * Destroys the instance. * * @public */ HSNavigationPush.prototype.destroy = function() { var _self = this; if(this.overlay) this.overlay.remove(); if(this.toggler && this.toggler.length) this.toggler.hide(); if( $.HSCore.components.HSScrollBar ) { setTimeout(function(){ $.HSCore.components.HSScrollBar.destroy( _self.element.find( '.u-main-nav__list-wrapper' ) ); }, 10); } setTimeout(function(){ if(_self.transitionDuration && _self.transitionDuration > 0) { _self.element.off("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend"); } },50); this.body.removeClass( this.bodyClasses ).removeClass(this.config.navigationInitBodyClasses); this.element .removeClass('u-main-nav--push') .removeClass(this.config.navigationInitClasses); this._unbindEvents(); this.isInit = false; }; /** * Binds necessary events. * * @private */ HSNavigationPush.prototype._bindEvents = function() { var _self = this; if(this.toggler && this.toggler.length) { this.toggler.on('click.HSNavigation', function(e){ if(_self.isOpened) { _self.close(); } else { _self.open(); } e.preventDefault(); }); } this.overlay.on('click.HSNavigation', function(e){ _self.close(); }); $(document).on('keyup.HSNavigation', function(e){ if(e.keyCode == 27) { _self.close(); } }); }; /** * Unbinds necessary events. * * @private */ HSNavigationPush.prototype._unbindEvents = function() { if(this.toggler && this.toggler.length) { this.toggler.off('click.HSNavigation'); } if(this.overlay && this.overlay.length) { this.overlay.off('click.HSNavigation'); } $(document).off('keyup.HSNavigation'); }; /** * Shows the navigation. * * @public */ HSNavigationPush.prototype.open = function() { this.body.addClass( this.config.activeClass ); if(this.transitionDuration !== undefined && this.transitionDuration == 0) { this.config.afterOpen.call(this.element, this.overlay); } }; /** * Hides the navigation. * * @public */ HSNavigationPush.prototype.close = function() { var hamburgers = this.toggler && this.toggler.length ? this.toggler.find('.is-active') : $(); if(hamburgers.length) hamburgers.removeClass('is-active'); this.body.removeClass( this.config.activeClass ); if(this.transitionDuration !== undefined && this.transitionDuration == 0) { this.config.afterClose.call(this.element, this.overlay); } }; /** * Returns true if the navigation has been initialized. * * @public * @return {Boolean} */ HSNavigationPush.prototype.isInitialized = function() { return this.isInit; }; })(jQuery);