UNPKG

mikit-framework

Version:

A web framework for professional developers and designers alike.

216 lines (188 loc) 6.14 kB
/** * @library Mikit Dropdown * @author Mikit * @license MIT */ (function (Mikit) { Mikit.Dropdown = function (element, options) { this.namespace = 'dropdown'; this.defaults = { target: null, toggleEvent: 'click', height: false, // integer width: false, // integer animationOpen: 'slideDown', animationClose: 'slideUp', caretUp: false, callbacks: ['open', 'opened', 'close', 'closed'] }; // Parent Constructor Mikit.apply(this, arguments); // Services this.utils = new Mikit.Utils(); this.detect = new Mikit.Detect(); // Initialization this.start(); }; // Functionality Mikit.Dropdown.prototype = { start: function () { this.buildClose(); this.buildCaret(); if (this.detect.isMobile()) this.buildMobileAnimation(); this.$target.addClass('mi-hide'); this.$element.on(this.opts.toggleEvent + '.' + this.namespace, $.proxy(this.toggle, this)); }, stop: function () { this.$element.off('.' + this.namespace); this.$target.removeClass('mi-open').addClass('mi-hide'); this.disableEvents(); }, buildMobileAnimation: function () { this.opts.animationOpen = 'fadeIn'; this.opts.animationClose = 'fadeOut'; }, buildClose: function () { this.$close = this.$target.find('.mi-close'); }, buildCaret: function () { this.$caret = this.getCaret(); this.buildCaretPosition(); }, buildCaretPosition: function () { var height = this.$element.offset().top + this.$element.innerHeight() + this.$target.innerHeight(); if ($(document).height() > height) { return; } this.opts.caretUp = true; this.$caret.addClass('mi-up'); }, getCaret: function () { return this.$element.find('.mi-caret'); }, toggleCaretOpen: function () { if (this.opts.caretUp) this.$caret.removeClass('mi-up').addClass('mi-down'); else this.$caret.removeClass('mi-down').addClass('mi-up'); }, toggleCaretClose: function () { if (this.opts.caretUp) this.$caret.removeClass('mi-down').addClass('mi-up'); else this.$caret.removeClass('mi-up').addClass('mi-down'); }, toggle: function (e) { if (this.isOpened()) this.close(e); else this.open(e); }, open: function (e) { if (e) e.preventDefault(); this.callback('open'); $('.mi-dropdown').removeClass('mi-open').addClass('mi-hide'); if (this.opts.height) this.$target.css('min-height', this.opts.height + 'px'); if (this.opts.width) this.$target.width(this.opts.width); this.setPosition(); this.toggleCaretOpen(); this.$target.animation(this.opts.animationOpen, $.proxy(this.onOpened, this)); }, close: function (e) { if (!this.isOpened()) { return; } if (e) { if (this.shouldNotBeClosed(e.target)) { return; } e.preventDefault(); } this.utils.enableBodyScroll(); this.callback('close'); this.toggleCaretClose(); this.$target.animation(this.opts.animationClose, $.proxy(this.onClosed, this)); }, onClosed: function () { this.$target.removeClass('mi-open'); this.disableEvents(); this.callback('closed'); }, onOpened: function () { this.$target.addClass('mi-open'); this.enableEvents(); this.callback('opened'); }, isOpened: function () { return (this.$target.hasClass('mi-open')); }, enableEvents: function () { /* if (this.detect.isDesktop()) { this.$target.on('mouseover.' + this.namespace, $.proxy(this.utils.disableBodyScroll, this.utils)).on('mouseout.' + this.namespace, $.proxy(this.utils.enableBodyScroll, this.utils)); } */ $(document).on('scroll.' + this.namespace, $.proxy(this.setPosition, this)); $(window).on('resize.' + this.namespace, $.proxy(this.setPosition, this)); $(document).on('click.' + this.namespace + ' touchstart.' + this.namespace, $.proxy(this.close, this)); $(document).on('keydown.' + this.namespace, $.proxy(this.handleKeyboard, this)); this.$target.find('[data-action="dropdown-close"]').on('click.' + this.namespace, $.proxy(this.close, this)); }, disableEvents: function () { this.$target.off('.' + this.namespace); $(document).off('.' + this.namespace); $(window).off('.' + this.namespace); }, handleKeyboard: function (e) { if (e.which === 27) this.close(e); }, shouldNotBeClosed: function (el) { if ($(el).attr('data-action') === 'dropdown-close' || el === this.$close[0]) { return false; } else if ($(el).closest('.mi-dropdown').length === 0) { return false; } return true; }, isNavigationFixed: function () { return (this.$element.closest('.mi-fixed').length !== 0); }, getPlacement: function (height) { return ($(document).height() < height) ? 'top' : 'bottom'; }, getOffset: function (position) { return (this.isNavigationFixed()) ? this.$element.position() : this.$element.offset(); }, getPosition: function () { return (this.isNavigationFixed()) ? 'fixed' : 'absolute'; }, setPosition: function () { if (this.detect.isMobile()) { this.$target.addClass('mi-dropdown-mobile'); return; } var position = this.getPosition(); var coords = this.getOffset(position); var height = this.$target.innerHeight(); var width = this.$target.innerWidth(); var placement = this.getPlacement(coords.top + height + this.$element.innerHeight()); var leftFix = ($(window).width() < (coords.left + width)) ? (width - this.$element.innerWidth()) : 0; var top, left = coords.left - leftFix; if (placement === 'bottom') { if (!this.isOpened()) this.$caret.removeClass('mi-up').addClass('mi-down'); this.opts.caretUp = false; top = coords.top + this.$element.outerHeight() + 1; } else { this.opts.animationOpen = 'show'; this.opts.animationClose = 'hide'; if (!this.isOpened()) this.$caret.addClass('mi-up').removeClass('mi-down'); this.opts.caretUp = true; top = coords.top - height - 1; } this.$target.css({ position: position, top: top + 'px', left: left + 'px' }); } }; // Inheritance Mikit.Dropdown.inherits(Mikit); // Plugin Mikit.Plugin.create('Dropdown'); Mikit.Plugin.autoload('Dropdown'); }(Mikit));