From 29b0f55e8ec9f0fcf3f4c992107b0bbfea753b65 Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Thu, 6 Sep 2018 00:50:06 +0200 Subject: [PATCH 1/7] configure hover-delay ... ... via e.g.: "data-dropdown-hover-delay=500" --- js/bootstrap-dropdownhover.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/bootstrap-dropdownhover.js b/js/bootstrap-dropdownhover.js index bb65f6e..088a451 100644 --- a/js/bootstrap-dropdownhover.js +++ b/js/bootstrap-dropdownhover.js @@ -99,10 +99,11 @@ var that = this var $this = $(_dropdownLink) var $parent = $this.parent() + var $this_delay = $this.data('dropdown-hover-delay'); Dropdownhover.TIMEOUT = window.setTimeout(function () { $parent.removeClass('open') $this.attr('aria-expanded', false) - }, Dropdownhover.DELAY) + }, ($this_delay ? $this_delay : Dropdownhover.DELAY)) } // Calculating position of dropdown menu From 450c3e8ad93474d977ac3ee2e3b279f766a1284a Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Thu, 20 Dec 2018 11:47:35 +0100 Subject: [PATCH 2/7] [+]: fix for "bounds === undefined" [+]: do not close the menu, if you switch between menu and sub-menu --- js/bootstrap-dropdownhover.js | 339 +++++++++++++++++++++------------- 1 file changed, 209 insertions(+), 130 deletions(-) diff --git a/js/bootstrap-dropdownhover.js b/js/bootstrap-dropdownhover.js index 2738241..c13e023 100644 --- a/js/bootstrap-dropdownhover.js +++ b/js/bootstrap-dropdownhover.js @@ -5,183 +5,246 @@ * Licensed under MIT (https://github.com/kybarg/bootstrap-dropdown-hover/blob/master/LICENSE) * ======================================================================== */ - +function ($) { 'use strict'; // DROPDOWN CLASS DEFINITION // ========================= - var backdrop = '.dropdown-backdrop' + var backdrop = '.dropdown-backdrop'; var Dropdownhover = function (element, options) { - this.options = options - this.$element = $(element) + this.options = options; + this.$element = $(element); - var that = this + var that = this; // Defining if navigation tree or single dropdown - this.dropdowns = this.$element.hasClass('dropdown-toggle') ? this.$element.parent().find('.dropdown-menu').parent('.dropdown') : this.$element.find('.dropdown') + this.dropdowns = this.$element.hasClass('dropdown-toggle') ? this.$element.parent().find('.dropdown-menu').parent('.dropdown') : this.$element.find('.dropdown'); if (!options.onClick) { - this.dropdowns.each(function () { - $(this).on('mouseenter.bs.dropdownhover', function (e) { + + this.dropdowns.each(function() { + $(this).on('mouseenter.bs.dropdownhover', function(e) { that.show($(this).children('a, button')) }) - }) + }); - this.dropdowns.each(function () { - $(this).on('mouseleave.bs.dropdownhover', function (e) { + this.dropdowns.each(function() { + $(this).on('mouseleave.bs.dropdownhover', function(e) { that.hide($(this).children('a, button')) }) }) + } else { - this.dropdowns.each(function () { + + this.dropdowns.each(function() { $(this).children('a, button').on('click.bs.dropdownhover', function (e) { - var isActive = $(this).parent().hasClass('open') + var isActive = $(this).parent().hasClass('open'); isActive ? that.hide($(this)) : that.show($(this)) }) }) + } - } + }; - Dropdownhover.TRANSITION_DURATION = 300 - Dropdownhover.DELAY = 150 - Dropdownhover.TIMEOUT + Dropdownhover.TRANSITION_DURATION = 300; + Dropdownhover.DELAY = 150; + Dropdownhover.TIMEOUT_SHOW; + Dropdownhover.TIMEOUT_HIDE; Dropdownhover.DEFAULTS = { onClick: false, - animations: ['fadeInDown', 'fadeInRight', 'fadeInUp', 'fadeInLeft'], - } - + animations: [ + 'fadeInDown', + 'fadeInRight', + 'fadeInUp', + 'fadeInLeft' + ] + }; + + /** + * @param $this + * + * @returns {{length}|*|jQuery} + */ function getParent($this) { - var selector = $this.attr('data-target') + var selector = $this.attr('data-target'); if (!selector) { - selector = $this.attr('href') + selector = $this.attr('href'); selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 } - var $parent = selector && $(document).find(selector) + var $parent = selector && $(document).find(selector); return $parent && $parent.length ? $parent : $this.parent() } + /** + * @param e + */ function clearMenus(e) { - if (e && e.which === 3) return - $(backdrop).remove() - $('[data-hover="dropdown"]').each(function () { - var $this = $(this) - var $parent = getParent($this) - var relatedTarget = { relatedTarget: this } + if (e && e.which === 3) { + return; + } + + $(backdrop).remove(); + $('[data-hover="dropdown"]').each(function() { + var $this = $(this); + var $parent = getParent($this); + var relatedTarget = { relatedTarget: this }; - if (!$parent.hasClass('open')) return + if (!$parent.hasClass('open')) { + return; + } - if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return + if ( + e + && + e.type == 'click' + && + /input|textarea/i.test(e.target.tagName) + && + $.contains($parent[0], e.target) + ) { + return; + } - $parent.trigger(e = $.Event('hide.bs.dropdownhover', relatedTarget)) + $parent.trigger(e = $.Event('hide.bs.dropdownhover', relatedTarget)); - if (e.isDefaultPrevented()) return + if (e.isDefaultPrevented()) { + return; + } - $this.attr('aria-expanded', 'false') + $this.attr('aria-expanded', 'false'); $parent.removeClass('open').trigger($.Event('hidden.bs.dropdownhover', relatedTarget)) }) } - // Opens dropdown menu when mouse is over the trigger element + /** + * Opens dropdown menu when mouse is over the trigger element + * + * @param _dropdownLink + * + * @returns {boolean} + */ Dropdownhover.prototype.show = function (_dropdownLink) { - var $this = $(_dropdownLink) - - window.clearTimeout(Dropdownhover.TIMEOUT) - // Close all dropdowns - $('.dropdown').not($this.parents()).each(function () { - $(this).removeClass('open') - }); + var that = this; + var $this = $(_dropdownLink); + var $this_hover_delay = $this.data('dropdown-hover-delay'); - var effect = this.options.animations[0] + window.clearTimeout(Dropdownhover.TIMEOUT_HIDE); - if ($this.is('.disabled, :disabled')) return + Dropdownhover.TIMEOUT_SHOW = window.setTimeout(function() { - var $parent = $this.parent() - var isActive = $parent.hasClass('open') + // Close all dropdowns + $('.dropdown').not($this.parents()).each(function() { + $(this).removeClass('open') + }); - if (!isActive) { + var effect = that.options.animations[0]; - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { - // if mobile we use a backdrop because click events don't delegate - $(document.createElement('div')) - .addClass('dropdown-backdrop') - .insertAfter($(this)) - .on('click', clearMenus) + if ($this.is('.disabled, :disabled')) { + return; } - var $dropdown = $this.next('.dropdown-menu') + var $parent = $this.parent(); + var isActive = $parent.hasClass('open'); - $parent.addClass('open') - $this.attr('aria-expanded', true) + if (!isActive) { - // Ensures that all menus that are closed have proper aria tagging. - $parent.siblings().each(function () { - if (!$(this).hasClass('open')) { - $(this).find('[data-hover="dropdown"]').attr('aria-expanded', false); + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $(document.createElement('div')) + .addClass('dropdown-backdrop') + .insertAfter($(this)) + .on('click', clearMenus) } - }) - var side = this.position($dropdown) - - switch (side) { - case 'top': - effect = this.options.animations[2] - break; - case 'right': - effect = this.options.animations[3] - break; - case 'left': - effect = this.options.animations[1] - break; - default: - effect = this.options.animations[0] - break; - } + var $dropdown = $this.next('.dropdown-menu'); + + $parent.addClass('open'); + $this.attr('aria-expanded', true); + + // Ensures that all menus that are closed have proper aria tagging. + $parent.siblings().each(function() { + if (!$(that).hasClass('open')) { + $(that).find('[data-hover="dropdown"]').attr('aria-expanded', false); + } + }); + + var side = that.position($dropdown); + + switch (side) { + case 'top': + effect = that.options.animations[2]; + break; + case 'right': + effect = that.options.animations[3]; + break; + case 'left': + effect = that.options.animations[1]; + break; + default: + effect = that.options.animations[0]; + break; + } - $dropdown.addClass('animated ' + effect) + $dropdown.addClass('animated ' + effect); - var transition = $.support.transition && $dropdown.hasClass('animated') + var transition = $.support.transition && $dropdown.hasClass('animated'); - transition ? - $dropdown - .one('bsTransitionEnd', function () { + transition ? + $dropdown + .one('bsTransitionEnd', function() { + $dropdown.removeClass('animated ' + effect) + }) + .emulateTransitionEnd(Dropdownhover.TRANSITION_DURATION) : $dropdown.removeClass('animated ' + effect) - }) - .emulateTransitionEnd(Dropdownhover.TRANSITION_DURATION) : - $dropdown.removeClass('animated ' + effect) - } + } + + }, ($this_hover_delay) ? $this_hover_delay : Dropdownhover.DELAY); return false - } + }; + + /** + * Closes dropdown menu when mouse is out of it + * + * @param _dropdownLink + */ + Dropdownhover.prototype.hide = function(_dropdownLink) { + + var $this = $(_dropdownLink); + var $parent = $this.parent(); + var $this_hover_delay = $this.data('dropdown-hover-delay'); + + window.clearTimeout(Dropdownhover.TIMEOUT_SHOW); - // Closes dropdown menu when mouse is out of it - Dropdownhover.prototype.hide = function (_dropdownLink) { + Dropdownhover.TIMEOUT_HIDE = window.setTimeout(function() { - var that = this - var $this = $(_dropdownLink) - var $parent = $this.parent() - var $this_delay = $this.data('dropdown-hover-delay'); - Dropdownhover.TIMEOUT = window.setTimeout(function () { - $parent.removeClass('open') + $parent.removeClass('open'); $this.attr('aria-expanded', false) - }, ($this_delay ? $this_delay : Dropdownhover.DELAY)) - } - // Calculating position of dropdown menu - Dropdownhover.prototype.position = function (dropdown) { + }, ($this_hover_delay ? $this_hover_delay : Dropdownhover.DELAY)); + }; + + /** + * Calculating position of dropdown menu + * + * @param dropdown + * + * @returns {string} + */ + Dropdownhover.prototype.position = function(dropdown) { var win = $(window); // Reset css to prevent incorrect position - dropdown.css({ bottom: '', left: '', top: '', right: '' }).removeClass('dropdownhover-top') + dropdown.css({ bottom: '', left: '', top: '', right: '' }).removeClass('dropdownhover-top'); var viewport = { top: win.scrollTop(), @@ -191,31 +254,36 @@ viewport.bottom = viewport.top + win.height(); var bounds = dropdown.offset(); + if (bounds === undefined) { + // fallback hack + side = 'right'; + return side; + } bounds.right = bounds.left + dropdown.outerWidth(); bounds.bottom = bounds.top + dropdown.outerHeight(); var position = dropdown.position(); position.right = bounds.left + dropdown.outerWidth(); position.bottom = bounds.top + dropdown.outerHeight(); - var side = '' + var side = ''; - var isSubnow = dropdown.parents('.dropdown-menu').length + var isSubnow = dropdown.parents('.dropdown-menu').length; if (isSubnow) { if (position.left < 0) { - side = 'left' + side = 'left'; dropdown.removeClass('dropdownhover-right').addClass('dropdownhover-left') } else { - side = 'right' + side = 'right'; dropdown.addClass('dropdownhover-right').removeClass('dropdownhover-left') } if (bounds.left < viewport.left) { - side = 'right' + side = 'right'; dropdown.css({ left: '100%', right: 'auto' }).addClass('dropdownhover-right').removeClass('dropdownhover-left') } else if (bounds.right > viewport.right) { - side = 'left' + side = 'left'; dropdown.css({ left: 'auto', right: '100%' }).removeClass('dropdownhover-right').addClass('dropdownhover-left') } @@ -227,67 +295,78 @@ } else { // Defines special position styles for root dropdown menu - var parentLi = dropdown.parent('.dropdown') - var pBounds = parentLi.offset() - pBounds.right = pBounds.left + parentLi.outerWidth() - pBounds.bottom = pBounds.top + parentLi.outerHeight() + var parentLi = dropdown.parent('.dropdown'); + var pBounds = parentLi.offset(); + pBounds.right = pBounds.left + parentLi.outerWidth(); + pBounds.bottom = pBounds.top + parentLi.outerHeight(); if (bounds.right > viewport.right) { dropdown.css({ left: -(bounds.right - viewport.right), right: 'auto' }) } if (bounds.bottom > viewport.bottom && (pBounds.top - viewport.top) > (viewport.bottom - pBounds.bottom) || dropdown.position().top < 0) { - side = 'top' + side = 'top'; dropdown.css({ bottom: '100%', top: 'auto' }).addClass('dropdownhover-top').removeClass('dropdownhover-bottom') } else { - side = 'bottom' + side = 'bottom'; dropdown.addClass('dropdownhover-bottom') } } return side; - } + }; // DROPDOWNHOVER PLUGIN DEFINITION // ========================== + /** + * @param option + * + * @returns {*} + * + * @constructor + */ function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.dropdownhover') - var settings = $this.data() - if ($this.data('animations') !== undefined && $this.data('animations') !== null) - settings.animations = $.isArray(settings.animations) ? settings.animations : settings.animations.split(' ') + return this.each(function() { + var $this = $(this); + var data = $this.data('bs.dropdownhover'); + var settings = $this.data(); - var options = $.extend({}, Dropdownhover.DEFAULTS, settings, typeof option == 'object' && option) + if ($this.data('animations') !== undefined && $this.data('animations') !== null) { + settings.animations = $.isArray(settings.animations) ? settings.animations : settings.animations.split(' '); + } + + var options = $.extend({}, Dropdownhover.DEFAULTS, settings, typeof option == 'object' && option); - if (!data) $this.data('bs.dropdownhover', (data = new Dropdownhover(this, options))) + if (!data) { + $this.data('bs.dropdownhover', (data = new Dropdownhover(this, options))); + } }) } - var old = $.fn.dropdownhover + var old = $.fn.dropdownhover; - $.fn.dropdownhover = Plugin - $.fn.dropdownhover.Constructor = Dropdownhover + $.fn.dropdownhover = Plugin; + $.fn.dropdownhover.Constructor = Dropdownhover; // DROPDOWNHOVER NO CONFLICT // ==================== - $.fn.dropdownhover.noConflict = function () { - $.fn.dropdownhover = old + $.fn.dropdownhover.noConflict = function() { + $.fn.dropdownhover = old; return this - } + }; // APPLY TO STANDARD DROPDOWNHOVER ELEMENTS // =================================== - $(document).ready(function () { - $('[data-hover="dropdown"]').each(function () { - var $target = $(this) + $(document).ready(function() { + $('[data-hover="dropdown"]').each(function() { + var $target = $(this); if ('ontouchstart' in document.documentElement) { Plugin.call($target, $.extend({}, $target.data(), { onClick: true })) } else { From 36b75969d5e485a77a0db412dd49eae5d1d5568d Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Thu, 20 Dec 2018 11:54:31 +0100 Subject: [PATCH 3/7] [*]: sync the code-style --- js/bootstrap-dropdownhover.js | 93 ++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/js/bootstrap-dropdownhover.js b/js/bootstrap-dropdownhover.js index c13e023..a2d6cd4 100644 --- a/js/bootstrap-dropdownhover.js +++ b/js/bootstrap-dropdownhover.js @@ -5,7 +5,7 @@ * Licensed under MIT (https://github.com/kybarg/bootstrap-dropdown-hover/blob/master/LICENSE) * ======================================================================== */ -+function ($) { ++function($) { 'use strict'; // DROPDOWN CLASS DEFINITION @@ -13,8 +13,8 @@ var backdrop = '.dropdown-backdrop'; - var Dropdownhover = function (element, options) { - this.options = options; + var Dropdownhover = function(element, options) { + this.options = options; this.$element = $(element); var that = this; @@ -39,7 +39,7 @@ } else { this.dropdowns.each(function() { - $(this).children('a, button').on('click.bs.dropdownhover', function (e) { + $(this).children('a, button').on('click.bs.dropdownhover', function(e) { var isActive = $(this).parent().hasClass('open'); isActive ? that.hide($(this)) : that.show($(this)) }) @@ -50,12 +50,12 @@ }; Dropdownhover.TRANSITION_DURATION = 300; - Dropdownhover.DELAY = 150; + Dropdownhover.DELAY = 150; Dropdownhover.TIMEOUT_SHOW; Dropdownhover.TIMEOUT_HIDE; Dropdownhover.DEFAULTS = { - onClick: false, + onClick: false, animations: [ 'fadeInDown', 'fadeInRight', @@ -92,8 +92,8 @@ $(backdrop).remove(); $('[data-hover="dropdown"]').each(function() { - var $this = $(this); - var $parent = getParent($this); + var $this = $(this); + var $parent = getParent($this); var relatedTarget = { relatedTarget: this }; if (!$parent.hasClass('open')) { @@ -130,10 +130,10 @@ * * @returns {boolean} */ - Dropdownhover.prototype.show = function (_dropdownLink) { + Dropdownhover.prototype.show = function(_dropdownLink) { - var that = this; - var $this = $(_dropdownLink); + var that = this; + var $this = $(_dropdownLink); var $this_hover_delay = $this.data('dropdown-hover-delay'); window.clearTimeout(Dropdownhover.TIMEOUT_HIDE); @@ -151,7 +151,7 @@ return; } - var $parent = $this.parent(); + var $parent = $this.parent(); var isActive = $parent.hasClass('open'); if (!isActive) { @@ -218,8 +218,8 @@ */ Dropdownhover.prototype.hide = function(_dropdownLink) { - var $this = $(_dropdownLink); - var $parent = $this.parent(); + var $this = $(_dropdownLink); + var $parent = $this.parent(); var $this_hover_delay = $this.data('dropdown-hover-delay'); window.clearTimeout(Dropdownhover.TIMEOUT_SHOW); @@ -244,13 +244,18 @@ var win = $(window); // Reset css to prevent incorrect position - dropdown.css({ bottom: '', left: '', top: '', right: '' }).removeClass('dropdownhover-top'); - - var viewport = { - top: win.scrollTop(), + dropdown.css({ + bottom: '', + left: '', + top: '', + right: '' + }).removeClass('dropdownhover-top'); + + var viewport = { + top: win.scrollTop(), left: win.scrollLeft() }; - viewport.right = viewport.left + win.width(); + viewport.right = viewport.left + win.width(); viewport.bottom = viewport.top + win.height(); var bounds = dropdown.offset(); @@ -259,10 +264,10 @@ side = 'right'; return side; } - bounds.right = bounds.left + dropdown.outerWidth(); - bounds.bottom = bounds.top + dropdown.outerHeight(); - var position = dropdown.position(); - position.right = bounds.left + dropdown.outerWidth(); + bounds.right = bounds.left + dropdown.outerWidth(); + bounds.bottom = bounds.top + dropdown.outerHeight(); + var position = dropdown.position(); + position.right = bounds.left + dropdown.outerWidth(); position.bottom = bounds.top + dropdown.outerHeight(); var side = ''; @@ -281,32 +286,50 @@ if (bounds.left < viewport.left) { side = 'right'; - dropdown.css({ left: '100%', right: 'auto' }).addClass('dropdownhover-right').removeClass('dropdownhover-left') + dropdown.css({ + left: '100%', + right: 'auto' + }).addClass('dropdownhover-right').removeClass('dropdownhover-left') } else if (bounds.right > viewport.right) { side = 'left'; - dropdown.css({ left: 'auto', right: '100%' }).removeClass('dropdownhover-right').addClass('dropdownhover-left') + dropdown.css({ + left: 'auto', + right: '100%' + }).removeClass('dropdownhover-right').addClass('dropdownhover-left') } if (bounds.bottom > viewport.bottom) { - dropdown.css({ bottom: 'auto', top: -(bounds.bottom - viewport.bottom) }) + dropdown.css({ + bottom: 'auto', + top: -(bounds.bottom - viewport.bottom) + }) } else if (bounds.top < viewport.top) { - dropdown.css({ bottom: -(viewport.top - bounds.top), top: 'auto' }) + dropdown.css({ + bottom: -(viewport.top - bounds.top), + top: 'auto' + }) } } else { // Defines special position styles for root dropdown menu - var parentLi = dropdown.parent('.dropdown'); - var pBounds = parentLi.offset(); - pBounds.right = pBounds.left + parentLi.outerWidth(); + var parentLi = dropdown.parent('.dropdown'); + var pBounds = parentLi.offset(); + pBounds.right = pBounds.left + parentLi.outerWidth(); pBounds.bottom = pBounds.top + parentLi.outerHeight(); if (bounds.right > viewport.right) { - dropdown.css({ left: -(bounds.right - viewport.right), right: 'auto' }) + dropdown.css({ + left: -(bounds.right - viewport.right), + right: 'auto' + }) } if (bounds.bottom > viewport.bottom && (pBounds.top - viewport.top) > (viewport.bottom - pBounds.bottom) || dropdown.position().top < 0) { side = 'top'; - dropdown.css({ bottom: '100%', top: 'auto' }).addClass('dropdownhover-top').removeClass('dropdownhover-bottom') + dropdown.css({ + bottom: '100%', + top: 'auto' + }).addClass('dropdownhover-top').removeClass('dropdownhover-bottom') } else { side = 'bottom'; dropdown.addClass('dropdownhover-bottom') @@ -330,8 +353,8 @@ */ function Plugin(option) { return this.each(function() { - var $this = $(this); - var data = $this.data('bs.dropdownhover'); + var $this = $(this); + var data = $this.data('bs.dropdownhover'); var settings = $this.data(); if ($this.data('animations') !== undefined && $this.data('animations') !== null) { @@ -349,7 +372,7 @@ var old = $.fn.dropdownhover; - $.fn.dropdownhover = Plugin; + $.fn.dropdownhover = Plugin; $.fn.dropdownhover.Constructor = Dropdownhover; From b5a9c1927ffa79684166e8c50cdadc5244d59261 Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Thu, 20 Dec 2018 12:01:36 +0100 Subject: [PATCH 4/7] [*]: sync the code-style v2 --- js/bootstrap-dropdownhover.js | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/js/bootstrap-dropdownhover.js b/js/bootstrap-dropdownhover.js index a2d6cd4..0f269f0 100644 --- a/js/bootstrap-dropdownhover.js +++ b/js/bootstrap-dropdownhover.js @@ -19,8 +19,12 @@ var that = this; - // Defining if navigation tree or single dropdown - this.dropdowns = this.$element.hasClass('dropdown-toggle') ? this.$element.parent().find('.dropdown-menu').parent('.dropdown') : this.$element.find('.dropdown'); + // defining if navigation tree or single dropdown + if (this.$element.hasClass('dropdown-toggle')) { + this.dropdowns = this.$element.parent().find('.dropdown-menu').parent('.dropdown'); + } else { + this.dropdowns = this.$element.find('.dropdown'); + } if (!options.onClick) { @@ -67,7 +71,7 @@ /** * @param $this * - * @returns {{length}|*|jQuery} + * @returns {*} */ function getParent($this) { var selector = $this.attr('data-target'); @@ -103,7 +107,7 @@ if ( e && - e.type == 'click' + e.type === 'click' && /input|textarea/i.test(e.target.tagName) && @@ -124,7 +128,7 @@ } /** - * Opens dropdown menu when mouse is over the trigger element + * Opens dropdown menu when mouse is over the trigger element. * * @param _dropdownLink * @@ -140,7 +144,7 @@ Dropdownhover.TIMEOUT_SHOW = window.setTimeout(function() { - // Close all dropdowns + // close all dropdowns $('.dropdown').not($this.parents()).each(function() { $(this).removeClass('open') }); @@ -212,7 +216,7 @@ }; /** - * Closes dropdown menu when mouse is out of it + * Closes dropdown menu when mouse is out of it. * * @param _dropdownLink */ @@ -233,7 +237,7 @@ }; /** - * Calculating position of dropdown menu + * Calculating position of dropdown menu. * * @param dropdown * @@ -243,7 +247,7 @@ var win = $(window); - // Reset css to prevent incorrect position + // reset css to prevent incorrect position dropdown.css({ bottom: '', left: '', @@ -310,7 +314,7 @@ }) } - } else { // Defines special position styles for root dropdown menu + } else { // defines special position styles for root dropdown menu var parentLi = dropdown.parent('.dropdown'); var pBounds = parentLi.offset(); @@ -324,7 +328,13 @@ }) } - if (bounds.bottom > viewport.bottom && (pBounds.top - viewport.top) > (viewport.bottom - pBounds.bottom) || dropdown.position().top < 0) { + if ( + bounds.bottom > viewport.bottom + && + (pBounds.top - viewport.top) > (viewport.bottom - pBounds.bottom) + || + dropdown.position().top < 0 + ) { side = 'top'; dropdown.css({ bottom: '100%', @@ -375,16 +385,13 @@ $.fn.dropdownhover = Plugin; $.fn.dropdownhover.Constructor = Dropdownhover; - // DROPDOWNHOVER NO CONFLICT // ==================== - $.fn.dropdownhover.noConflict = function() { $.fn.dropdownhover = old; return this }; - // APPLY TO STANDARD DROPDOWNHOVER ELEMENTS // =================================== $(document).ready(function() { From 23bc9d92c58b4193a97667534f103cef93be2e37 Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Thu, 20 Dec 2018 12:16:59 +0100 Subject: [PATCH 5/7] [+]: keep css if "auto !important" is used --- js/bootstrap-dropdownhover.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/js/bootstrap-dropdownhover.js b/js/bootstrap-dropdownhover.js index 0f269f0..5609fc8 100644 --- a/js/bootstrap-dropdownhover.js +++ b/js/bootstrap-dropdownhover.js @@ -322,10 +322,22 @@ pBounds.bottom = pBounds.top + parentLi.outerHeight(); if (bounds.right > viewport.right) { - dropdown.css({ - left: -(bounds.right - viewport.right), - right: 'auto' - }) + var styleTmp = dropdown.attr('style'); + // keep css if "auto !important" is used + if ( + styleTmp + && + ( + styleTmp.indexOf('left: auto !important;') === -1 + && + styleTmp.indexOf('right: auto !important;') === -1 + ) + ) { + dropdown.css({ + left: -(bounds.right - viewport.right), + right: 'auto' + }); + } } if ( From a81d562a6f57a5c97f76ef3bfdd11bfd91b906a6 Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Tue, 8 Oct 2019 09:35:06 +0200 Subject: [PATCH 6/7] Update bootstrap-dropdownhover.js --- js/bootstrap-dropdownhover.js | 753 ++++++++++++++++++---------------- 1 file changed, 394 insertions(+), 359 deletions(-) diff --git a/js/bootstrap-dropdownhover.js b/js/bootstrap-dropdownhover.js index 5609fc8..aba1c79 100644 --- a/js/bootstrap-dropdownhover.js +++ b/js/bootstrap-dropdownhover.js @@ -1,420 +1,455 @@ /* ======================================================================== - * Bootstrap: dropdownhover.js v1.1.0 + * Bootstrap: dropdownhover.js v1.1.x * http://kybarg.github.io/bootstrap-dropdown-hover/ * ======================================================================== * Licensed under MIT (https://github.com/kybarg/bootstrap-dropdown-hover/blob/master/LICENSE) * ======================================================================== */ +function($) { - 'use strict'; + 'use strict'; - // DROPDOWN CLASS DEFINITION - // ========================= + // DROPDOWN CLASS DEFINITION + // ========================= - var backdrop = '.dropdown-backdrop'; + var backdrop = '.dropdown-backdrop'; - var Dropdownhover = function(element, options) { - this.options = options; - this.$element = $(element); + var Dropdownhover = function(element, options) { + this.options = options; + this.$element = $(element); - var that = this; + var that = this; - // defining if navigation tree or single dropdown - if (this.$element.hasClass('dropdown-toggle')) { - this.dropdowns = this.$element.parent().find('.dropdown-menu').parent('.dropdown'); - } else { - this.dropdowns = this.$element.find('.dropdown'); - } + // defining if navigation tree or single dropdown + if (this.$element.hasClass('dropdown-toggle')) { + this.dropdowns = this.$element.parent().find('.dropdown-menu').parent('.dropdown'); + } else { + this.dropdowns = this.$element.find('.dropdown'); + } - if (!options.onClick) { + // this.dropdowns contains all "li" elements which have a submenu - this.dropdowns.each(function() { - $(this).on('mouseenter.bs.dropdownhover', function(e) { - that.show($(this).children('a, button')) - }) - }); + // this.options contains a onClick property which contains that the actual browser fires touch events, but this isn't used - this.dropdowns.each(function() { - $(this).on('mouseleave.bs.dropdownhover', function(e) { - that.hide($(this).children('a, button')) - }) - }) + this.dropdowns.each(function() { - } else { + $(this).children('a, button').on('touchstart', function(e) { - this.dropdowns.each(function() { - $(this).children('a, button').on('click.bs.dropdownhover', function(e) { - var isActive = $(this).parent().hasClass('open'); - isActive ? that.hide($(this)) : that.show($(this)) - }) - }) + // console.log('Dropdownhover - options.onClick - touchstart'); - } + $(this).attr('data-touchstart-event', 'true'); - }; - - Dropdownhover.TRANSITION_DURATION = 300; - Dropdownhover.DELAY = 150; - Dropdownhover.TIMEOUT_SHOW; - Dropdownhover.TIMEOUT_HIDE; - - Dropdownhover.DEFAULTS = { - onClick: false, - animations: [ - 'fadeInDown', - 'fadeInRight', - 'fadeInUp', - 'fadeInLeft' - ] - }; - - /** - * @param $this - * - * @returns {*} - */ - function getParent($this) { - var selector = $this.attr('data-target'); - - if (!selector) { - selector = $this.attr('href'); - selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } + }).on('click', function(e) { - var $parent = selector && $(document).find(selector); + // console.log('Dropdownhover - options.onClick - click', e); - return $parent && $parent.length ? $parent : $this.parent() - } + var touchstartEvent = $(this).attr('data-touchstart-event'); - /** - * @param e - */ - function clearMenus(e) { - if (e && e.which === 3) { - return; - } + if (touchstartEvent === 'true') { - $(backdrop).remove(); - $('[data-hover="dropdown"]').each(function() { - var $this = $(this); - var $parent = getParent($this); - var relatedTarget = { relatedTarget: this }; - - if (!$parent.hasClass('open')) { - return; - } - - if ( - e - && - e.type === 'click' - && - /input|textarea/i.test(e.target.tagName) - && - $.contains($parent[0], e.target) - ) { - return; - } - - $parent.trigger(e = $.Event('hide.bs.dropdownhover', relatedTarget)); - - if (e.isDefaultPrevented()) { - return; - } - - $this.attr('aria-expanded', 'false'); - $parent.removeClass('open').trigger($.Event('hidden.bs.dropdownhover', relatedTarget)) - }) - } + var isActive = $(this).parent().hasClass('open'); + var showMenu = $(this).attr('data-show-menu'); + if (!isActive && showMenu !== 'true') { + that.show($(this)); + e.preventDefault(); + + // Hack: Stop immediate to disable all followed event handlers, to stop that bootstrap offcanvas + // can interfer with the menu. This will also stop all further event handler. + e.stopImmediatePropagation(); + + } else { + var href = $(this).attr('href'); + if (!href) { + that.hide($(this)); + } + } - /** - * Opens dropdown menu when mouse is over the trigger element. - * - * @param _dropdownLink - * - * @returns {boolean} - */ - Dropdownhover.prototype.show = function(_dropdownLink) { + // console.log('Dropdownhover - options.onClick - click - touched', e); + } - var that = this; - var $this = $(_dropdownLink); - var $this_hover_delay = $this.data('dropdown-hover-delay'); + }); - window.clearTimeout(Dropdownhover.TIMEOUT_HIDE); + $(this).on('mouseenter.bs.dropdownhover', function(e) { - Dropdownhover.TIMEOUT_SHOW = window.setTimeout(function() { + // console.log('Dropdownhover - !options.onClick - mouseenter.bs.dropdownhover', e.target); - // close all dropdowns - $('.dropdown').not($this.parents()).each(function() { - $(this).removeClass('open') - }); + that.show($(this).children('a, button')) - var effect = that.options.animations[0]; + }).on('mouseleave.bs.dropdownhover', function(e) { - if ($this.is('.disabled, :disabled')) { - return; - } + // console.log('Dropdownhover - !options.onClick - mouseleave.bs.dropdownhover', e.target); - var $parent = $this.parent(); - var isActive = $parent.hasClass('open'); + that.hide($(this).children('a, button')) - if (!isActive) { + }) + }) + + }; - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { - // if mobile we use a backdrop because click events don't delegate - $(document.createElement('div')) - .addClass('dropdown-backdrop') - .insertAfter($(this)) - .on('click', clearMenus) + Dropdownhover.TRANSITION_DURATION = 300; + Dropdownhover.DELAY_SHOW = 250; + Dropdownhover.DELAY_HIDE = 800; + Dropdownhover.TIMEOUT_SHOW; + Dropdownhover.TIMEOUT_HIDE; + + Dropdownhover.DEFAULTS = { + onClick: false, + animations: [ + 'fadeInDown', + 'fadeInRight', + 'fadeInUp', + 'fadeInLeft' + ] + }; + + /** + * @param $this + * + * @returns {*} + */ + function getParent($this) { + var selector = $this.attr('data-target'); + + if (!selector) { + selector = $this.attr('href'); + selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 } - var $dropdown = $this.next('.dropdown-menu'); - - $parent.addClass('open'); - $this.attr('aria-expanded', true); - - // Ensures that all menus that are closed have proper aria tagging. - $parent.siblings().each(function() { - if (!$(that).hasClass('open')) { - $(that).find('[data-hover="dropdown"]').attr('aria-expanded', false); - } - }); - - var side = that.position($dropdown); - - switch (side) { - case 'top': - effect = that.options.animations[2]; - break; - case 'right': - effect = that.options.animations[3]; - break; - case 'left': - effect = that.options.animations[1]; - break; - default: - effect = that.options.animations[0]; - break; + var $parent = selector && $(document).find(selector); + + return $parent && $parent.length ? $parent : $this.parent() + } + + /** + * @param e + */ + function clearMenus(e) { + if (e && e.which === 3) { + return; } - $dropdown.addClass('animated ' + effect); + $(backdrop).remove(); + $('[data-hover="dropdown"]').each(function() { + var $this = $(this); + var $parent = getParent($this); + var relatedTarget = { relatedTarget: this }; - var transition = $.support.transition && $dropdown.hasClass('animated'); + if (!$parent.hasClass('open')) { + return; + } - transition ? - $dropdown - .one('bsTransitionEnd', function() { - $dropdown.removeClass('animated ' + effect) - }) - .emulateTransitionEnd(Dropdownhover.TRANSITION_DURATION) : - $dropdown.removeClass('animated ' + effect) - } - - }, ($this_hover_delay) ? $this_hover_delay : Dropdownhover.DELAY); - - return false - }; - - /** - * Closes dropdown menu when mouse is out of it. - * - * @param _dropdownLink - */ - Dropdownhover.prototype.hide = function(_dropdownLink) { - - var $this = $(_dropdownLink); - var $parent = $this.parent(); - var $this_hover_delay = $this.data('dropdown-hover-delay'); - - window.clearTimeout(Dropdownhover.TIMEOUT_SHOW); - - Dropdownhover.TIMEOUT_HIDE = window.setTimeout(function() { - - $parent.removeClass('open'); - $this.attr('aria-expanded', false) - - }, ($this_hover_delay ? $this_hover_delay : Dropdownhover.DELAY)); - }; - - /** - * Calculating position of dropdown menu. - * - * @param dropdown - * - * @returns {string} - */ - Dropdownhover.prototype.position = function(dropdown) { - - var win = $(window); - - // reset css to prevent incorrect position - dropdown.css({ - bottom: '', - left: '', - top: '', - right: '' - }).removeClass('dropdownhover-top'); - - var viewport = { - top: win.scrollTop(), - left: win.scrollLeft() - }; - viewport.right = viewport.left + win.width(); - viewport.bottom = viewport.top + win.height(); - - var bounds = dropdown.offset(); - if (bounds === undefined) { - // fallback hack - side = 'right'; - return side; + if ( + e + && + e.type === 'click' + && + /input|textarea/i.test(e.target.tagName) + && + $.contains($parent[0], e.target) + ) { + return; + } + + $parent.trigger(e = $.Event('hide.bs.dropdownhover', relatedTarget)); + + if (e.isDefaultPrevented()) { + return; + } + + $this.attr('aria-expanded', 'false'); + $parent.removeClass('open').trigger($.Event('hidden.bs.dropdownhover', relatedTarget)) + }) } - bounds.right = bounds.left + dropdown.outerWidth(); - bounds.bottom = bounds.top + dropdown.outerHeight(); - var position = dropdown.position(); - position.right = bounds.left + dropdown.outerWidth(); - position.bottom = bounds.top + dropdown.outerHeight(); - var side = ''; + /** + * Opens dropdown menu when mouse is over the trigger element. + * + * @param _dropdownLink + * + * @returns {boolean} + */ + Dropdownhover.prototype.show = function(_dropdownLink) { + + var that = this; + var $this = $(_dropdownLink); + + window.clearTimeout(Dropdownhover.TIMEOUT_HIDE); + + Dropdownhover.TIMEOUT_SHOW = window.setTimeout(function() { + + // close all dropdowns + $('.dropdown').not($this.parents()).each(function() { + $(this).removeClass('open') + }); + + var effect = that.options.animations[0]; + + if ($this.is('.disabled, :disabled')) { + return; + } + + var $parent = $this.parent(); + var isActive = $parent.hasClass('open'); + + if (!isActive) { + + if ('ontouchstart' in document.documentElement && $parent.closest('.navbar-nav').length > 0) { + + // if mobile we use a backdrop because click events don't delegate + // + // it will also be append to the dom multiple times, but if you click on the menu entry the site + // will be reloaded or if you click outsite of the menu all dom elements will be removed + $(document.createElement('div')) + .addClass('dropdown-backdrop') + .on('click', clearMenus) + .appendTo('body'); + } + + var $dropdown = $this.next('.dropdown-menu'); + + $parent.addClass('open'); + $this.attr('aria-expanded', true); + + // Ensures that all menus that are closed have proper aria tagging. + $parent.siblings().each(function() { + if (!$(that).hasClass('open')) { + $(that).find('[data-hover="dropdown"]').attr('aria-expanded', false); + } + }); + + var side = that.position($dropdown); + + switch (side) { + case 'top': + effect = that.options.animations[2]; + break; + case 'right': + effect = that.options.animations[3]; + break; + case 'left': + effect = that.options.animations[1]; + break; + default: + effect = that.options.animations[0]; + break; + } + + $dropdown.addClass('animated ' + effect); + + var transition = $.support.transition && $dropdown.hasClass('animated'); + + transition ? + $dropdown + .one('bsTransitionEnd', function() { + $dropdown.removeClass('animated ' + effect) + }) + .emulateTransitionEnd(Dropdownhover.TRANSITION_DURATION) : + $dropdown.removeClass('animated ' + effect) + } + + }, Dropdownhover.DELAY_SHOW); + + return false + }; - var isSubnow = dropdown.parents('.dropdown-menu').length; + /** + * Closes dropdown menu when mouse is out of it. + * + * @param _dropdownLink + */ + Dropdownhover.prototype.hide = function(_dropdownLink) { - if (isSubnow) { + var $this = $(_dropdownLink); + var $parent = $this.parent(); - if (position.left < 0) { - side = 'left'; - dropdown.removeClass('dropdownhover-right').addClass('dropdownhover-left') - } else { - side = 'right'; - dropdown.addClass('dropdownhover-right').removeClass('dropdownhover-left') - } + window.clearTimeout(Dropdownhover.TIMEOUT_SHOW); - if (bounds.left < viewport.left) { - side = 'right'; - dropdown.css({ - left: '100%', - right: 'auto' - }).addClass('dropdownhover-right').removeClass('dropdownhover-left') - } else if (bounds.right > viewport.right) { - side = 'left'; - dropdown.css({ - left: 'auto', - right: '100%' - }).removeClass('dropdownhover-right').addClass('dropdownhover-left') - } + Dropdownhover.TIMEOUT_HIDE = window.setTimeout(function() { - if (bounds.bottom > viewport.bottom) { - dropdown.css({ - bottom: 'auto', - top: -(bounds.bottom - viewport.bottom) - }) - } else if (bounds.top < viewport.top) { + $parent.removeClass('open'); + $this.attr('aria-expanded', false) + + }, Dropdownhover.DELAY_HIDE); + }; + + /** + * Calculating position of dropdown menu. + * + * @param dropdown + * + * @returns {string} + */ + Dropdownhover.prototype.position = function(dropdown) { + + var win = $(window); + + // reset css to prevent incorrect position dropdown.css({ - bottom: -(viewport.top - bounds.top), - top: 'auto' - }) - } - - } else { // defines special position styles for root dropdown menu - - var parentLi = dropdown.parent('.dropdown'); - var pBounds = parentLi.offset(); - pBounds.right = pBounds.left + parentLi.outerWidth(); - pBounds.bottom = pBounds.top + parentLi.outerHeight(); - - if (bounds.right > viewport.right) { - var styleTmp = dropdown.attr('style'); - // keep css if "auto !important" is used - if ( - styleTmp - && - ( - styleTmp.indexOf('left: auto !important;') === -1 + bottom: '', + left: '', + top: '', + right: '' + }).removeClass('dropdownhover-top'); + + var viewport = { + top: win.scrollTop(), + left: win.scrollLeft() + }; + viewport.right = viewport.left + win.width(); + viewport.bottom = viewport.top + win.height(); + + var bounds = dropdown.offset(); + if (bounds === undefined) { + // fallback hack + side = 'right'; + return side; + } + bounds.right = bounds.left + dropdown.outerWidth(); + bounds.bottom = bounds.top + dropdown.outerHeight(); + var position = dropdown.position(); + position.right = bounds.left + dropdown.outerWidth(); + position.bottom = bounds.top + dropdown.outerHeight(); + + var side = ''; + + var isSubnow = dropdown.parents('.dropdown-menu').length; + + if (isSubnow) { + + if (position.left < 0) { + side = 'left'; + dropdown.removeClass('dropdownhover-right').addClass('dropdownhover-left') + } else { + side = 'right'; + dropdown.addClass('dropdownhover-right').removeClass('dropdownhover-left') + } + + if (bounds.left < viewport.left) { + side = 'right'; + dropdown.css({ + left: '100%', + right: 'auto' + }).addClass('dropdownhover-right').removeClass('dropdownhover-left') + } else if (bounds.right > viewport.right) { + side = 'left'; + dropdown.css({ + left: 'auto', + right: '100%' + }).removeClass('dropdownhover-right').addClass('dropdownhover-left') + } + + if (bounds.bottom > viewport.bottom) { + dropdown.css({ + bottom: 'auto', + top: -(bounds.bottom - viewport.bottom) + }) + } else if (bounds.top < viewport.top) { + dropdown.css({ + bottom: -(viewport.top - bounds.top), + top: 'auto' + }) + } + + } else { // defines special position styles for root dropdown menu + + var parentLi = dropdown.parent('.dropdown'); + var pBounds = parentLi.offset(); + pBounds.right = pBounds.left + parentLi.outerWidth(); + pBounds.bottom = pBounds.top + parentLi.outerHeight(); + + if (bounds.right > viewport.right) { + var styleTmp = dropdown.attr('style'); + // keep css if "auto !important" is used + if ( + styleTmp + && + ( + styleTmp.indexOf('left: auto !important;') === -1 + && + styleTmp.indexOf('right: auto !important;') === -1 + ) + ) { + dropdown.css({ + left: -(bounds.right - viewport.right), + right: 'auto' + }); + } + } + + if ( + bounds.bottom > viewport.bottom && - styleTmp.indexOf('right: auto !important;') === -1 - ) - ) { - dropdown.css({ - left: -(bounds.right - viewport.right), - right: 'auto' - }); + (pBounds.top - viewport.top) > (viewport.bottom - pBounds.bottom) + || + dropdown.position().top < 0 + ) { + side = 'top'; + dropdown.css({ + bottom: '100%', + top: 'auto' + }).addClass('dropdownhover-top').removeClass('dropdownhover-bottom') + } else { + side = 'bottom'; + dropdown.addClass('dropdownhover-bottom') + } } - } - - if ( - bounds.bottom > viewport.bottom - && - (pBounds.top - viewport.top) > (viewport.bottom - pBounds.bottom) - || - dropdown.position().top < 0 - ) { - side = 'top'; - dropdown.css({ - bottom: '100%', - top: 'auto' - }).addClass('dropdownhover-top').removeClass('dropdownhover-bottom') - } else { - side = 'bottom'; - dropdown.addClass('dropdownhover-bottom') - } - } - return side; + return side; - }; + }; - // DROPDOWNHOVER PLUGIN DEFINITION - // ========================== + // DROPDOWNHOVER PLUGIN DEFINITION + // ========================== - /** - * @param option - * - * @returns {*} - * - * @constructor - */ - function Plugin(option) { - return this.each(function() { - var $this = $(this); - var data = $this.data('bs.dropdownhover'); - var settings = $this.data(); + /** + * @param option + * + * @returns {*} + * + * @constructor + */ + function Plugin(option) { + return this.each(function() { + var $this = $(this); + var data = $this.data('bs.dropdownhover'); + var settings = $this.data(); - if ($this.data('animations') !== undefined && $this.data('animations') !== null) { - settings.animations = $.isArray(settings.animations) ? settings.animations : settings.animations.split(' '); - } + if ($this.data('animations') !== undefined && $this.data('animations') !== null) { + settings.animations = $.isArray(settings.animations) ? settings.animations : settings.animations.split(' '); + } - var options = $.extend({}, Dropdownhover.DEFAULTS, settings, typeof option == 'object' && option); + var options = $.extend({}, Dropdownhover.DEFAULTS, settings, typeof option == 'object' && option); - if (!data) { - $this.data('bs.dropdownhover', (data = new Dropdownhover(this, options))); - } + if (!data) { + $this.data('bs.dropdownhover', (data = new Dropdownhover(this, options))); + } + }) + } + + var old = $.fn.dropdownhover; + + $.fn.dropdownhover = Plugin; + $.fn.dropdownhover.Constructor = Dropdownhover; + + // DROPDOWNHOVER NO CONFLICT + // ==================== + $.fn.dropdownhover.noConflict = function() { + $.fn.dropdownhover = old; + return this + }; + + // APPLY TO STANDARD DROPDOWNHOVER ELEMENTS + // =================================== + $(document).ready(function() { + $('[data-hover="dropdown"]').each(function() { + var $target = $(this); + if ('ontouchstart' in document.documentElement) { + Plugin.call($target, $.extend({}, $target.data(), { onClick: true })) + } else { + Plugin.call($target, $target.data()) + } + }) }) - } - - var old = $.fn.dropdownhover; - - $.fn.dropdownhover = Plugin; - $.fn.dropdownhover.Constructor = Dropdownhover; - - // DROPDOWNHOVER NO CONFLICT - // ==================== - $.fn.dropdownhover.noConflict = function() { - $.fn.dropdownhover = old; - return this - }; - - // APPLY TO STANDARD DROPDOWNHOVER ELEMENTS - // =================================== - $(document).ready(function() { - $('[data-hover="dropdown"]').each(function() { - var $target = $(this); - if ('ontouchstart' in document.documentElement) { - Plugin.call($target, $.extend({}, $target.data(), { onClick: true })) - } else { - Plugin.call($target, $target.data()) - } - }) - }) }(jQuery); From 777741d729c90614b1d7be02c96bb6169918179b Mon Sep 17 00:00:00 2001 From: Lars Moelleken Date: Tue, 8 Oct 2019 09:38:10 +0200 Subject: [PATCH 7/7] Update bootstrap-dropdownhover.css --- css/bootstrap-dropdownhover.css | 130 ++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 47 deletions(-) diff --git a/css/bootstrap-dropdownhover.css b/css/bootstrap-dropdownhover.css index 0cb9adf..a6d21bf 100644 --- a/css/bootstrap-dropdownhover.css +++ b/css/bootstrap-dropdownhover.css @@ -1,35 +1,33 @@ -/*! +/* --------------------------------------------------------- */ +/* * Dropdownhover v1.0.0 (http://bs-dropdownhover.kybarg.com) */ -.dropdown .dropdown-menu .caret { - border: 4px solid transparent; - border-left-color: #000; - float: right; - margin-top: 6px; -} -.dropdown-menu { - min-width: 250px; -} -.dropdown-menu > li.open > a { - background-color: #F5F5F5; - color: #262626; - text-decoration: none; -} -.dropdown-menu .dropdown-menu { - left: 100%; - margin: 0; - right: auto; - top: -1px; -} -.dropdown-menu-right .dropdown-menu, -.navbar-right .dropdown-menu .dropdown-menu, -.pull-right .dropdown-menu .dropdown-menu { - left: auto; - right: 100%; +/* --------------------------------------------------------- */ + +/** + * add animation for bootstrap "dropdown-menu" + * + * @see: + * Animation duration: http://www.w3schools.com/cssref/css3_pr_animation-duration.asp + * Animation timing: http://www.w3schools.com/cssref/css3_pr_animation-timing-function.asp + */ + +.dropdown > a { + -webkit-transition: all 0.2s ease-in; + -o-transition: all 0.2s ease-in; + -moz-transition: all 0.2s ease-in; + transition: all 0.2s ease-in; } + .dropdown-menu.animated { -webkit-animation-duration: 0.3s; - animation-duration: 0.3s; + -moz-animation-duration: 0.3s; + -o-animation-duration: 0.3s; + animation-duration: 0.3s; + -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);; + -moz-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);; + -o-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);; + animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1);; } .dropdown-menu.animated:before { content: " "; @@ -41,33 +39,71 @@ width: 100%; z-index: 99; } -.dropdownhover-top { - margin-bottom: 2px; - margin-top: 0; -} -.navbar-fixed-bottom .dropdown-menu .dropdown-menu, -.dropdownhover-top .dropdown-menu { - bottom: -1px; - top: auto; -} -.navbar-nav > li > .dropdown-menu { - margin-bottom: 0; +.dropdown-menu.animated.fadeIn { + -webkit-animation-duration: 0.2s; + -moz-animation-duration: 0.2s; + -o-animation-duration: 0.2s; + animation-duration: 0.2s; + -webkit-animation-timing-function: ease-out; + -moz-animation-timing-function: ease-out; + -o-animation-timing-function: ease-out; + animation-timing-function: ease-out; } .dropdownhover-bottom { - -webkit-transform-origin: 50% 0; - transform-origin: 50% 0; + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + /* <-- use the GPU for the rendering */ + -webkit-transform-origin: 50% 0; + -moz-transform-origin: 50% 0; + -ms-transform-origin: 50% 0; + -o-transform-origin: 50% 0; + transform-origin: 50% 0; } + .dropdownhover-left { - -webkit-transform-origin: 100% 50%; - transform-origin: 100% 50%; + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + /* <-- use the GPU for the rendering */ + -webkit-transform-origin: 100% 50%; + -moz-transform-origin: 100% 50%; + -ms-transform-origin: 100% 50%; + -o-transform-origin: 100% 50%; + transform-origin: 100% 50%; } + .dropdownhover-right { - -webkit-transform-origin: 0 50%; - transform-origin: 0 50%; + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + /* <-- use the GPU for the rendering */ + -webkit-transform-origin: 0 50%; + -moz-transform-origin: 0 50%; + -ms-transform-origin: 0 50%; + -o-transform-origin: 0 50%; + transform-origin: 0 50%; } + .dropdownhover-top { - -webkit-transform-origin: 50% 100%; - transform-origin: 50% 100%; -} \ No newline at end of file + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + /* <-- use the GPU for the rendering */ + -webkit-transform-origin: 50% 100%; + -moz-transform-origin: 50% 100%; + -ms-transform-origin: 50% 100%; + -o-transform-origin: 50% 100%; + transform-origin: 50% 100%; +} +