2022-09-08 08:04:32 -07:00

690 lines
15 KiB
JavaScript

/**
* 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 = $('<div></div>', {
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 = $('<div></div>', {
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);