From 90de67a177afdb575d950601a2ecdbe88a989f97 Mon Sep 17 00:00:00 2001 From: Nicolas Coden Date: Tue, 24 Jul 2018 23:57:34 +0200 Subject: [PATCH] refactor: make the magic mouseleave utility a simple event filter --- js/foundation.core.utils.js | 70 ++++++++++++++++++----------------- js/foundation.dropdownMenu.js | 8 ++-- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/js/foundation.core.utils.js b/js/foundation.core.utils.js index 3cef14d91..2fffbe3b1 100644 --- a/js/foundation.core.utils.js +++ b/js/foundation.core.utils.js @@ -91,46 +91,48 @@ function onLoad($elem, handler) { } /** - * Watch for the mouse leaving the jQuery element `$elem` and triggers the given `handler` it so. - * When the mouse desapear from the document (like when going on a browser UI element, See https://git.io/zf-11410), - * nothing is triggered. If the mouse reapear later on the document outside of `$elem`, the given handler is triggered. + * Retuns an handler for the `mouseleave` that ignore disappeared mouses. * - * If the `leaveWindow` option is `true` (by default), the given handler is triggered when the mouse desapeared because - * the window lost focus (like with [Alt]+[Tab]). + * If the mouse "disappeared" from the document (like when going on a browser UI element, See https://git.io/zf-11410), + * the event is ignored. + * - If the `ignoreLeaveWindow` is `true`, the event is ignored when the user actually left the window + * (like by switching to an other window with [Alt]+[Tab]). + * - If the `ignoreReappear` is `true`, the event will be ignored when the mouse will reappear later on the document + * outside of the element it left. * * @function * - * @param {Object} [] $elem - jQuery element to watch. - * @param {Function} [] handler - function to trigger when the mouse left the element. - * @param {Object} [{leaveWindow = true}] object - options - * @returns {String} - event type attached to the given element. + * @param {Function} [] handler - handler for the filtered `mouseleave` event to watch. + * @param {Object} [] options - object of options: + * - {Boolean} [false] ignoreLeaveWindow - also ignore when the user switched windows. + * - {Boolean} [false] ignoreReappear - also ignore when the mouse reappeared outside of the element it left. + * @returns {Function} - filtered handler to use to listen on the `mouseleave` event. */ -function onLeaveElement($elem, handler, { leaveWindow = true } = {}) { - const eventType = 'mouseleave.zf.util.onLeaveElement'; - - if ($elem && handler) { - - $elem.on(eventType, function leaveHandler(e, ...rest) { - const _this = this; - setTimeout(function leaveEventDebouncer() { - - if (e.relatedTarget === null && leaveWindow && document.hasFocus && document.hasFocus()) { - - $(document).one('mouseenter', function reenterHandler(reeenterE) { - if ($elem.has(reeenterE.target).length) { return false }; - e.relatedTarget = reeenterE.target; - handler.call(_this, e, ...rest); - }); - - return false; - } - - handler.call(_this, e, ...rest); - }); +function ignoreMousedisappear(handler, { ignoreLeaveWindow = false, ignoreReappear = false } = {}) { + return function leaveEventHandler(eEnter, ...rest) { + const callback = handler.bind(this, eEnter, ...rest); + setTimeout(function leaveEventDebouncer() { + + if (eEnter.relatedTarget !== null + // - if the user switched to an other window (and we don't ignore it) + || !ignoreLeaveWindow && document.hasFocus && !document.hasFocus()) { + callback(); + } + + else if (!ignoreReappear) { + $(document).one('mouseenter', function reenterEventHandler(eReenter) { + if (!$(eEnter.currentTarget).has(eReenter.target).length) { + + eEnter.relatedTarget = eReenter.target; + callback(); + + } + }); + } }); - } - return eventType; + }; } -export {rtl, GetYoDigits, RegExpEscape, transitionend, onLoad, onLeaveElement}; + +export {rtl, GetYoDigits, RegExpEscape, transitionend, onLoad, ignoreMousedisappear}; diff --git a/js/foundation.dropdownMenu.js b/js/foundation.dropdownMenu.js index 96f66fb13..aa25271b7 100644 --- a/js/foundation.dropdownMenu.js +++ b/js/foundation.dropdownMenu.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import { Plugin } from './foundation.core.plugin'; -import { rtl as Rtl, onLeaveElement } from './foundation.core.utils'; +import { rtl as Rtl, ignoreMousedisappear } from './foundation.core.utils'; import { Keyboard } from './foundation.util.keyboard'; import { Nest } from './foundation.util.nest'; import { Box } from './foundation.util.box'; @@ -149,9 +149,7 @@ class DropdownMenu extends Plugin { _this._show($elem.children('.is-dropdown-submenu')); }, _this.options.hoverDelay)); } - }); - - onLeaveElement(this.$menuItems, function (e) { + }).on('mouseleave.zf.dropdownMenu', ignoreMousedisappear(function (e) { var $elem = $(this), hasSub = $elem.hasClass(parClass); if (hasSub && _this.options.autoclose) { @@ -162,7 +160,7 @@ class DropdownMenu extends Plugin { _this._hide($elem); }, _this.options.closingTime)); } - }); + })); } this.$menuItems.on('keydown.zf.dropdownMenu', function(e) { var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'), -- 2.47.2