luci-0.11: merge r9399-r9402 and r9412
[project/luci.git] / themes / base / htdocs / luci-static / resources / Dropdowns.js
1 /*
2 Copyright (C) 2008 Alina Friedrichsen <x-alina@gmx.net>
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7 1. Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 2. Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12
13 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 SUCH DAMAGE.
24 */
25
26 function initDropdowns() {
27 var aSelects = XHTML1.getElementsByTagName("select");
28 var isIE6 = false /*@cc_on || @_jscript_version < 5.7 @*/;
29
30 function showPlaceholder(sel) {
31 if( ! sel._ph ) {
32 var box = sel.getBoundingClientRect();
33 sel._dm = sel.currentStyle.display;
34 sel._ph = document.createElement('input');
35 sel.parentNode.insertBefore(sel._ph, sel);
36 sel._ph.style.width = ( box.right - box.left ) + 'px';
37 sel._ph.style.height = ( box.bottom - box.top ) + 'px';
38 sel._ph.style.margin = sel.currentStyle.margin;
39 }
40
41 sel._ph.value = sel.options[sel.selectedIndex].text;
42 sel._ph.style.display = sel._dm;
43 sel.style.display = 'none';
44 }
45
46 function hidePlaceholder(sel) {
47 if( sel._ph ) sel._ph.style.display = 'none';
48 sel.style.display = sel._dm;
49 }
50
51 function hideSelects() {
52 for(var i = 0; i < aSelects.length; i++) {
53 showPlaceholder(aSelects[i]);
54 }
55 }
56
57 function showSelects() {
58 for(var i = 0; i < aSelects.length; i++) {
59 hidePlaceholder(aSelects[i]);
60 }
61 }
62
63 function isEmptyObject(obj) {
64 for(var i in obj) {
65 return false;
66 }
67 return true;
68 }
69
70 var nextUniqueID = 1;
71 var elementsNeeded = {};
72 var menusShown = {};
73 var menusToHide = {};
74 var delayHideTimerId;
75 var delayHideAllTime = 1000;
76 var delayHideTime = 400;
77 function delayHide() {
78 for(var i in menusToHide) {
79 XHTML1.removeClass(menusToHide[i], "focus");
80 }
81 delayHideTimerId = null;
82 }
83
84 function updatePopup() {
85 if(isIE6) {
86 if(isEmptyObject(elementsNeeded)) {
87 showSelects();
88 }
89 else{
90 hideSelects();
91 }
92 }
93
94 var menusShownOld = menusShown;
95 menusShown = {};
96 for(var id in elementsNeeded) {
97 var element = elementsNeeded[id];
98 for(element = findLi(element); element; element = findLi(element.parentNode)) {
99 XHTML1.addClass(element, "focus");
100 if(!element.uniqueID) {
101 element.uniqueID = nextUniqueID++;
102 }
103 element.style.zIndex = 1000;
104 menusShown[element.uniqueID] = element;
105 delete menusToHide[element.uniqueID];
106 }
107 }
108 for(var id in menusShownOld) {
109 if(!menusShown[id]) {
110 if(delayHideTimerId) {
111 clearTimeout(delayHideTimerId);
112 delayHideTimerId = 0;
113 delayHide();
114 }
115 menusToHide[id] = menusShownOld[id];
116 menusToHide[id].style.zIndex = 999;
117 }
118 }
119 if(menusToHide || isEmptyObject(elementsNeeded)) {
120 if(delayHideTimerId) {
121 clearTimeout(delayHideTimerId);
122 }
123 delayHideTimerId = setTimeout(delayHide, isEmptyObject(elementsNeeded) ? delayHideAllTime : delayHideTime);
124 }
125 }
126
127 function findLi(element) {
128 for(; element; element = element.parentNode) {
129 if(XHTML1.isElement(element, "li")) {
130 return element;
131 }
132 }
133 }
134
135 function onmouseover(evt) {
136 var li = findLi(evt.currentTarget);
137 if(li && !li.focused) {
138 if(!li.uniqueID) {
139 li.uniqueID = nextUniqueID++;
140 }
141 elementsNeeded[li.uniqueID] = li;
142 }
143 XHTML1.addClass(evt.currentTarget, "over");
144 updatePopup();
145 }
146
147 function onmouseout(evt) {
148 var li = findLi(evt.currentTarget);
149 if(li && !li.focused && li.uniqueID) {
150 delete elementsNeeded[li.uniqueID];
151 }
152 XHTML1.removeClass(evt.currentTarget, "over");
153 updatePopup();
154 }
155
156 function onfocus(evt) {
157 var li = findLi(evt.currentTarget);
158 if(li) {
159 li.focused = true;
160 if(!li.uniqueID) {
161 li.uniqueID = nextUniqueID++;
162 }
163 elementsNeeded[li.uniqueID] = li;
164 }
165 updatePopup();
166 }
167
168 function onblur(evt) {
169 var li = findLi(evt.currentTarget);
170 if(li) {
171 li.focused = false;
172 delete elementsNeeded[li.uniqueID];
173 }
174 updatePopup();
175 }
176
177 var aElements = XHTML1.getElementsByTagName("a");
178 for(var i = 0; i < aElements.length; i++) {
179 var a = aElements[i];
180 for(var element = a.parentNode; element; element = element.parentNode) {
181 if(XHTML1.isElement(element, "ul") && XHTML1.containsClass(element, "dropdowns")) {
182 XHTML1.addEventListener(a, "focus", onfocus);
183 XHTML1.addEventListener(a, "blur", onblur);
184 XHTML1.addEventListener(a, "mouseover", onmouseover);
185 XHTML1.addEventListener(a, "mouseout", onmouseout);
186 break;
187 }
188 }
189 }
190
191 XHTML1.addEventListener(document, "click", function() {
192 if (delayHideTimerId) {
193 clearTimeout(delayHideTimerId);
194 delayHideTimerId = 0;
195 delayHide();
196 }
197 });
198 }
199
200 if(XHTML1.isDOMSupported()) {
201 XHTML1.addEventListener(window, "load", initDropdowns);
202 }