[795] | 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 |
---|