1 | // Title: tigra menu |
---|
2 | // Description: See the demo at url |
---|
3 | // URL: http://www.softcomplex.com/products/tigra_menu/ |
---|
4 | // Version: 2.0 (commented source) |
---|
5 | // Date: 04-05-2003 (mm-dd-yyyy) |
---|
6 | // Tech. Support: http://www.softcomplex.com/forum/forumdisplay.php?fid=40 |
---|
7 | // Notes: This script is free. Visit official site for further details. |
---|
8 | |
---|
9 | // -------------------------------------------------------------------------------- |
---|
10 | // global collection containing all menus on current page |
---|
11 | var A_MENUS = []; |
---|
12 | |
---|
13 | // -------------------------------------------------------------------------------- |
---|
14 | // menu class |
---|
15 | function menu (a_items, a_tpl, a_div) { |
---|
16 | this.menuOutput = ''; |
---|
17 | // browser check |
---|
18 | if (!document.body || !document.body.style) |
---|
19 | return; |
---|
20 | |
---|
21 | // store items structure |
---|
22 | this.a_config = a_items; |
---|
23 | |
---|
24 | // store template structure |
---|
25 | this.a_tpl = a_tpl; |
---|
26 | |
---|
27 | this.divAppend = a_div; |
---|
28 | |
---|
29 | // get menu id |
---|
30 | this.n_id = A_MENUS.length; |
---|
31 | |
---|
32 | // declare collections |
---|
33 | this.a_index = []; |
---|
34 | this.a_children = []; |
---|
35 | |
---|
36 | // assigh methods and event handlers |
---|
37 | this.expand = menu_expand; |
---|
38 | this.collapse = menu_collapse; |
---|
39 | |
---|
40 | this.onclick = menu_onclick; |
---|
41 | this.onmouseout = menu_onmouseout; |
---|
42 | this.onmouseover = menu_onmouseover; |
---|
43 | this.onmousedown = menu_onmousedown; |
---|
44 | |
---|
45 | // default level scope description structure |
---|
46 | this.a_tpl_def = { |
---|
47 | 'block_top' : 16, |
---|
48 | 'block_left' : 16, |
---|
49 | 'top' : 20, |
---|
50 | 'left' : 4, |
---|
51 | 'width' : 120, |
---|
52 | 'auto-width' : false, |
---|
53 | 'height' : 22, |
---|
54 | 'hide_delay' : 0, |
---|
55 | 'expd_delay' : 0, |
---|
56 | 'css' : { |
---|
57 | 'inner' : '', |
---|
58 | 'outer' : '' |
---|
59 | } |
---|
60 | }; |
---|
61 | |
---|
62 | // assign methods and properties required to imulate parent item |
---|
63 | this.getprop = function (s_key) { |
---|
64 | return this.a_tpl_def[s_key]; |
---|
65 | }; |
---|
66 | |
---|
67 | this.o_root = this; |
---|
68 | this.n_depth = -1; |
---|
69 | this.n_x = 0; |
---|
70 | this.n_y = 0; |
---|
71 | |
---|
72 | // init items recursively |
---|
73 | for (n_order = 0; n_order < a_items.length; n_order++) |
---|
74 | new menu_item(this, n_order); |
---|
75 | |
---|
76 | redoReference(this); |
---|
77 | |
---|
78 | // register self in global collection |
---|
79 | A_MENUS[this.n_id] = this; |
---|
80 | |
---|
81 | // make root level visible |
---|
82 | for (var n_order = 0; n_order < this.a_children.length; n_order++) |
---|
83 | { |
---|
84 | this.a_children[n_order].e_oelement.style.visibility = 'visible'; |
---|
85 | } |
---|
86 | |
---|
87 | if (this.a_children.length > 0) |
---|
88 | { |
---|
89 | var autoWidth = this.a_children[0].getprop('auto-width'); |
---|
90 | if (autoWidth) |
---|
91 | { |
---|
92 | function recursiveWidth(children) |
---|
93 | { |
---|
94 | var max = 10; |
---|
95 | for (var i = 0; i < children.length; i++) |
---|
96 | { |
---|
97 | if (children[i]['a_config'][0].length > max) |
---|
98 | max = children[i]['a_config'][0].length; |
---|
99 | } |
---|
100 | |
---|
101 | for (var i = 0; i < children.length; i++) |
---|
102 | { |
---|
103 | document.getElementById(children[i].e_oelement.id).style.width = max/1.34 + 'em'; |
---|
104 | if (children[i].a_children) |
---|
105 | recursiveWidth(children[i].a_children); |
---|
106 | } |
---|
107 | } |
---|
108 | |
---|
109 | recursiveWidth(this.a_children); |
---|
110 | } |
---|
111 | } |
---|
112 | } |
---|
113 | |
---|
114 | function redoReference(ref) |
---|
115 | { |
---|
116 | for (var i = 0; i < ref.a_index.length; i++) |
---|
117 | { |
---|
118 | ref.a_index[i].e_oelement = document.getElementById(ref.a_index[i].e_oelement.id); |
---|
119 | ref.a_index[i].e_ielement = document.getElementById(ref.a_index[i].e_ielement.id); |
---|
120 | } |
---|
121 | // ref.a_children[i].e_oelement = document.getElementById(ref.a_children[i].e_oelement.id); |
---|
122 | } |
---|
123 | |
---|
124 | // -------------------------------------------------------------------------------- |
---|
125 | function menu_collapse (n_id) { |
---|
126 | if ((n_id == undefined) && this.divAppend) |
---|
127 | this.divAppend.style.display = 'none'; |
---|
128 | |
---|
129 | // cancel item open delay |
---|
130 | clearTimeout(this.o_showtimer); |
---|
131 | |
---|
132 | // by default collapse to root level |
---|
133 | var n_tolevel = (n_id ? this.a_index[n_id].n_depth : 0); |
---|
134 | |
---|
135 | // hide all items over the level specified |
---|
136 | for (n_id = 0; n_id < this.a_index.length; n_id++) { |
---|
137 | var o_curritem = this.a_index[n_id]; |
---|
138 | if (o_curritem.n_depth > n_tolevel && o_curritem.b_visible) { |
---|
139 | o_curritem.e_oelement.style.visibility = 'hidden'; |
---|
140 | o_curritem.b_visible = false; |
---|
141 | } |
---|
142 | } |
---|
143 | |
---|
144 | // reset current item if mouse has gone out of items |
---|
145 | if (!n_id) |
---|
146 | this.o_current = null; |
---|
147 | } |
---|
148 | |
---|
149 | // -------------------------------------------------------------------------------- |
---|
150 | function menu_expand (n_id) { |
---|
151 | |
---|
152 | // expand only when mouse is over some menu item |
---|
153 | if (this.o_hidetimer) |
---|
154 | return; |
---|
155 | |
---|
156 | // lookup current item |
---|
157 | var o_item = this.a_index[n_id]; |
---|
158 | |
---|
159 | // close previously opened items |
---|
160 | if (this.o_current && this.o_current.n_depth >= o_item.n_depth) |
---|
161 | this.collapse(o_item.n_id); |
---|
162 | this.o_current = o_item; |
---|
163 | |
---|
164 | // exit if there are no children to open |
---|
165 | if (!o_item.a_children) |
---|
166 | return; |
---|
167 | |
---|
168 | // show direct child items |
---|
169 | for (var n_order = 0; n_order < o_item.a_children.length; n_order++) { |
---|
170 | var o_curritem = o_item.a_children[n_order]; |
---|
171 | o_curritem.e_oelement.style.visibility = 'visible'; |
---|
172 | o_curritem.b_visible = true; |
---|
173 | } |
---|
174 | } |
---|
175 | |
---|
176 | // -------------------------------------------------------------------------------- |
---|
177 | // |
---|
178 | // -------------------------------------------------------------------------------- |
---|
179 | function menu_onclick (n_id) { |
---|
180 | // don't go anywhere if item has no link defined |
---|
181 | return Boolean(this.a_index[n_id].a_config[1]); |
---|
182 | } |
---|
183 | |
---|
184 | // -------------------------------------------------------------------------------- |
---|
185 | function menu_onmouseout (n_id) { |
---|
186 | |
---|
187 | // lookup new item's object |
---|
188 | var o_item = this.a_index[n_id]; |
---|
189 | |
---|
190 | // apply rollout |
---|
191 | o_item.e_oelement.className = o_item.getstyle(0, 0); |
---|
192 | o_item.e_ielement.className = o_item.getstyle(1, 0); |
---|
193 | |
---|
194 | // update status line |
---|
195 | o_item.upstatus(7); |
---|
196 | |
---|
197 | // run mouseover timer |
---|
198 | this.o_hidetimer = setTimeout('A_MENUS['+ this.n_id +'].collapse();', |
---|
199 | o_item.getprop('hide_delay')); |
---|
200 | } |
---|
201 | |
---|
202 | // -------------------------------------------------------------------------------- |
---|
203 | function menu_onmouseover (n_id) { |
---|
204 | |
---|
205 | // cancel mouseoute menu close and item open delay |
---|
206 | clearTimeout(this.o_hidetimer); |
---|
207 | this.o_hidetimer = null; |
---|
208 | clearTimeout(this.o_showtimer); |
---|
209 | |
---|
210 | // lookup new item's object |
---|
211 | var o_item = this.a_index[n_id]; |
---|
212 | |
---|
213 | // update status line |
---|
214 | o_item.upstatus(); |
---|
215 | |
---|
216 | // apply rollover |
---|
217 | o_item.e_oelement.className = o_item.getstyle(0, 1); |
---|
218 | o_item.e_ielement.className = o_item.getstyle(1, 1); |
---|
219 | |
---|
220 | // if onclick open is set then no more actions required |
---|
221 | if (o_item.getprop('expd_delay') < 0) |
---|
222 | return; |
---|
223 | |
---|
224 | // run expand timer |
---|
225 | this.o_showtimer = setTimeout('A_MENUS['+ this.n_id +'].expand(' + n_id + ');', |
---|
226 | o_item.getprop('expd_delay')); |
---|
227 | |
---|
228 | } |
---|
229 | |
---|
230 | // -------------------------------------------------------------------------------- |
---|
231 | // called when mouse button is pressed on menu item |
---|
232 | // -------------------------------------------------------------------------------- |
---|
233 | function menu_onmousedown (n_id) { |
---|
234 | |
---|
235 | // lookup new item's object |
---|
236 | var o_item = this.a_index[n_id]; |
---|
237 | |
---|
238 | // apply mouse down style |
---|
239 | o_item.e_oelement.className = o_item.getstyle(0, 2); |
---|
240 | o_item.e_ielement.className = o_item.getstyle(1, 2); |
---|
241 | |
---|
242 | this.expand(n_id); |
---|
243 | // this.items[id].switch_style('onmousedown'); |
---|
244 | } |
---|
245 | |
---|
246 | |
---|
247 | // -------------------------------------------------------------------------------- |
---|
248 | // menu item Class |
---|
249 | function menu_item (o_parent, n_order) { |
---|
250 | |
---|
251 | // store parameters passed to the constructor |
---|
252 | this.n_depth = o_parent.n_depth + 1; |
---|
253 | this.a_config = o_parent.a_config[n_order + (this.n_depth ? 3 : 0)]; |
---|
254 | |
---|
255 | // return if required parameters are missing |
---|
256 | if (!this.a_config) return; |
---|
257 | |
---|
258 | // store info from parent item |
---|
259 | this.o_root = o_parent.o_root; |
---|
260 | this.o_parent = o_parent; |
---|
261 | this.n_order = n_order; |
---|
262 | this.divAppend = o_parent.divAppend; |
---|
263 | |
---|
264 | // register in global and parent's collections |
---|
265 | this.n_id = this.o_root.a_index.length; |
---|
266 | this.o_root.a_index[this.n_id] = this; |
---|
267 | o_parent.a_children[n_order] = this; |
---|
268 | |
---|
269 | // calculate item's coordinates |
---|
270 | var o_root = this.o_root, |
---|
271 | a_tpl = this.o_root.a_tpl; |
---|
272 | |
---|
273 | // assign methods |
---|
274 | this.getprop = mitem_getprop; |
---|
275 | this.getstyle = mitem_getstyle; |
---|
276 | this.upstatus = mitem_upstatus; |
---|
277 | |
---|
278 | this.n_x = n_order |
---|
279 | ? o_parent.a_children[n_order - 1].n_x + this.getprop('left') |
---|
280 | : o_parent.n_x + this.getprop('block_left'); |
---|
281 | |
---|
282 | this.n_y = n_order |
---|
283 | ? o_parent.a_children[n_order - 1].n_y + this.getprop('top') |
---|
284 | : o_parent.n_y + this.getprop('block_top'); |
---|
285 | |
---|
286 | // generate item's HMTL |
---|
287 | var menuText = |
---|
288 | '<a id="e' + o_root.n_id + '_' |
---|
289 | + this.n_id +'o" class="' + this.getstyle(0, 0) + '" href="' + this.a_config[1] + '"' |
---|
290 | + (this.a_config[2] && this.a_config[2]['tw'] ? ' target="' |
---|
291 | + this.a_config[2]['tw'] + '"' : '') + ' style="position: absolute; top: ' |
---|
292 | + this.n_y + 'px; left: ' + this.n_x + 'px; width: ' |
---|
293 | + this.getprop('width') + 'px; height: ' |
---|
294 | + this.getprop('height') + 'px; visibility: hidden;' |
---|
295 | +' z-index: ' + this.n_depth + ';" ' |
---|
296 | + 'onclick="return A_MENUS[' + o_root.n_id + '].onclick(' |
---|
297 | + this.n_id + ');" onmouseout="A_MENUS[' + o_root.n_id + '].onmouseout(' |
---|
298 | + this.n_id + ');" onmouseover="A_MENUS[' + o_root.n_id + '].onmouseover(' |
---|
299 | + this.n_id + ');" onmousedown="A_MENUS[' + o_root.n_id + '].onmousedown(' |
---|
300 | + this.n_id + ');"><div id="e' + o_root.n_id + '_' |
---|
301 | + this.n_id +'i" class="' + this.getstyle(1, 0) + '">' |
---|
302 | + this.a_config[0] + "</div></a>\n"; |
---|
303 | ; |
---|
304 | if (this.divAppend) |
---|
305 | this.divAppend.innerHTML += menuText; |
---|
306 | else |
---|
307 | document.write(menuText); |
---|
308 | |
---|
309 | this.e_ielement = document.getElementById('e' + o_root.n_id + '_' + this.n_id + 'i'); |
---|
310 | this.e_oelement = document.getElementById('e' + o_root.n_id + '_' + this.n_id + 'o'); |
---|
311 | |
---|
312 | this.b_visible = !this.n_depth; |
---|
313 | |
---|
314 | // no more initialization if leaf |
---|
315 | if (this.a_config.length < 4) |
---|
316 | return; |
---|
317 | |
---|
318 | // node specific methods and properties |
---|
319 | this.a_children = []; |
---|
320 | |
---|
321 | // init downline recursively |
---|
322 | for (var n_order = 0; n_order < this.a_config.length - 3; n_order++) |
---|
323 | new menu_item(this, n_order); |
---|
324 | } |
---|
325 | |
---|
326 | // -------------------------------------------------------------------------------- |
---|
327 | // reads property from template file, inherits from parent level if not found |
---|
328 | // ------------------------------------------------------------------------------------------ |
---|
329 | function mitem_getprop (s_key) { |
---|
330 | |
---|
331 | // check if value is defined for current level |
---|
332 | var s_value = null, |
---|
333 | a_level = this.o_root.a_tpl[this.n_depth]; |
---|
334 | |
---|
335 | // return value if explicitly defined |
---|
336 | if (a_level) |
---|
337 | s_value = a_level[s_key]; |
---|
338 | |
---|
339 | // request recursively from parent levels if not defined |
---|
340 | return (s_value == null ? this.o_parent.getprop(s_key) : s_value); |
---|
341 | } |
---|
342 | // -------------------------------------------------------------------------------- |
---|
343 | // reads property from template file, inherits from parent level if not found |
---|
344 | // ------------------------------------------------------------------------------------------ |
---|
345 | function mitem_getstyle (n_pos, n_state) { |
---|
346 | |
---|
347 | var a_css = this.getprop('css'); |
---|
348 | var a_oclass = a_css[n_pos ? 'inner' : 'outer']; |
---|
349 | |
---|
350 | // same class for all states |
---|
351 | if (typeof(a_oclass) == 'string') |
---|
352 | return a_oclass; |
---|
353 | |
---|
354 | // inherit class from previous state if not explicitly defined |
---|
355 | for (var n_currst = n_state; n_currst >= 0; n_currst--) |
---|
356 | if (a_oclass[n_currst]) |
---|
357 | return a_oclass[n_currst]; |
---|
358 | } |
---|
359 | |
---|
360 | // ------------------------------------------------------------------------------------------ |
---|
361 | // updates status bar message of the browser |
---|
362 | // ------------------------------------------------------------------------------------------ |
---|
363 | function mitem_upstatus (b_clear) { |
---|
364 | window.setTimeout("window.status=unescape('" + (b_clear |
---|
365 | ? '' |
---|
366 | : (this.a_config[2] && this.a_config[2]['sb'] |
---|
367 | ? escape(this.a_config[2]['sb']) |
---|
368 | : escape(this.a_config[0]) + (this.a_config[1] |
---|
369 | ? ' ('+ escape(this.a_config[1]) + ')' |
---|
370 | : ''))) + "')", 10); |
---|
371 | } |
---|
372 | |
---|
373 | // -------------------------------------------------------------------------------- |
---|
374 | // that's all folks |
---|