From b2a7b2497806ac300b24a618279bd08a072903c2 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Wed, 2 Dec 2009 12:36:03 +0000 Subject: [PATCH] themes/base: implement close delay for popup menus (#95) --- .../htdocs/luci-static/resources/Dropdowns.js | 122 ++++++++++++++---- 1 file changed, 98 insertions(+), 24 deletions(-) diff --git a/themes/base/htdocs/luci-static/resources/Dropdowns.js b/themes/base/htdocs/luci-static/resources/Dropdowns.js index ff2f0e665..8c07a6f2f 100644 --- a/themes/base/htdocs/luci-static/resources/Dropdowns.js +++ b/themes/base/htdocs/luci-static/resources/Dropdowns.js @@ -60,46 +60,118 @@ function initDropdowns() { } } - function onmouseover(evt) { - XHTML1.addClass(evt.currentTarget, "over"); - if( isIE6 ) hideSelects(); + function isEmptyObject(obj) { + for(var i in obj) { + return false; + } + return true; } - function onmouseout(evt) { - XHTML1.removeClass(evt.currentTarget, "over"); - if( isIE6 ) showSelects(); + var nextUniqueID = 1; + var elementsNeeded = {}; + var menusShown = {}; + var menusToHide = {}; + var delayHideTimerId; + var delayHideAllTime = 1000; + var delayHideTime = 400; + function delayHide() { + for(var i in menusToHide) { + XHTML1.removeClass(menusToHide[i], "focus"); + } + delayHideTimerId = null; } - function onfocus(evt) { - for(var element = evt.currentTarget; element; element = element.parentNode) { - if(XHTML1.isElement(element, "li")) { + function updatePopup() { + if(isIE6) { + if(isEmptyObject(elementsNeeded)) { + showSelects(); + } + else{ + hideSelects(); + } + } + + var menusShownOld = menusShown; + menusShown = {}; + for(var id in elementsNeeded) { + var element = elementsNeeded[id]; + for(element = findLi(element); element; element = findLi(element.parentNode)) { XHTML1.addClass(element, "focus"); + if(!element.uniqueID) { + element.uniqueID = nextUniqueID++; + } + element.style.zIndex = 1000; + menusShown[element.uniqueID] = element; + delete menusToHide[element.uniqueID]; + } + } + for(var id in menusShownOld) { + if(!menusShown[id]) { + if(delayHideTimerId) { + clearTimeout(delayHideTimerId); + delayHideTimerId = 0; + delayHide(); + } + menusToHide[id] = menusShownOld[id]; + menusToHide[id].style.zIndex = 999; + } + } + if(menusToHide || isEmptyObject(elementsNeeded)) { + if(delayHideTimerId) { + clearTimeout(delayHideTimerId); } + delayHideTimerId = setTimeout(delayHide, isEmptyObject(elementsNeeded) ? delayHideAllTime : delayHideTime); } - if( isIE6 ) hideSelects(); } - function onblur(evt) { - for(var element = evt.currentTarget; element; element = element.parentNode) { + function findLi(element) { + for(; element; element = element.parentNode) { if(XHTML1.isElement(element, "li")) { - XHTML1.removeClass(element, "focus"); + return element; } } - if( isIE6 ) showSelects(); } - if(document.all) { - var liElements = XHTML1.getElementsByTagName("li"); - for(var i = 0; i < liElements.length; i++) { - var li = liElements[i]; - for(var element = li.parentNode; element; element = element.parentNode) { - if(XHTML1.isElement(element, "ul") && XHTML1.containsClass(element, "dropdowns")) { - XHTML1.addEventListener(li, "mouseover", onmouseover); - XHTML1.addEventListener(li, "mouseout", onmouseout); - break; - } + function onmouseover(evt) { + var li = findLi(evt.currentTarget); + if(li && !li.focused) { + if(!li.uniqueID) { + li.uniqueID = nextUniqueID++; + } + elementsNeeded[li.uniqueID] = li; + } + XHTML1.addClass(evt.currentTarget, "over"); + updatePopup(); + } + + function onmouseout(evt) { + var li = findLi(evt.currentTarget); + if(li && !li.focused && li.uniqueID) { + delete elementsNeeded[li.uniqueID]; + } + XHTML1.removeClass(evt.currentTarget, "over"); + updatePopup(); + } + + function onfocus(evt) { + var li = findLi(evt.currentTarget); + if(li) { + li.focused = true; + if(!li.uniqueID) { + li.uniqueID = nextUniqueID++; } + elementsNeeded[li.uniqueID] = li; + } + updatePopup(); + } + + function onblur(evt) { + var li = findLi(evt.currentTarget); + if(li) { + li.focused = false; + delete elementsNeeded[li.uniqueID]; } + updatePopup(); } var aElements = XHTML1.getElementsByTagName("a"); @@ -109,6 +181,8 @@ function initDropdowns() { if(XHTML1.isElement(element, "ul") && XHTML1.containsClass(element, "dropdowns")) { XHTML1.addEventListener(a, "focus", onfocus); XHTML1.addEventListener(a, "blur", onblur); + XHTML1.addEventListener(a, "mouseover", onmouseover); + XHTML1.addEventListener(a, "mouseout", onmouseout); break; } } -- 2.25.1