themes/base: implement close delay for popup menus (#95)
authorJo-Philipp Wich <jow@openwrt.org>
Wed, 2 Dec 2009 12:36:03 +0000 (12:36 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Wed, 2 Dec 2009 12:36:03 +0000 (12:36 +0000)
themes/base/htdocs/luci-static/resources/Dropdowns.js

index ff2f0e66535ea4c761a4bce5fc0387a5ca346d09..8c07a6f2fcd8dee7bf63707622645b9900273c1f 100644 (file)
@@ -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;
                        }
                }