main/menu/menu.js

Go to the documentation of this file.
00001 // -*-C-*- //tell emacs to use the C mode
00002 
00003 // Title: tigra menu
00004 // Description: See the demo at url
00005 // URL: http://www.softcomplex.com/products/tigra_menu/
00006 // Version: 2.0 (commented source)
00007 // Date: 04-05-2003 (mm-dd-yyyy)
00008 // Contact: feedback@softcomplex.com (specify product title in the subject)
00009 // Tech. Support: http://www.softcomplex.com/forum/forumdisplay.php?fid=40
00010 // Notes: This script is free. Visit official site for further details.
00011 
00012 // --------------------------------------------------------------------------------
00013 // global collection containing all menus on current page
00014 var A_MENUS = [];
00015 
00016 // --------------------------------------------------------------------------------
00017 // menu class
00018 function menu (a_items, a_tpl) {
00019 
00020   // browser check
00021   if (!document.body || !document.body.style)
00022     return;
00023 
00024   // store items structure
00025   this.a_config = a_items;
00026 
00027   // store template structure
00028   this.a_tpl = a_tpl;
00029 
00030   // get menu id
00031   this.n_id = A_MENUS.length;
00032 
00033   // declare collections
00034   this.a_index = [];
00035   this.a_children = [];
00036 
00037   // assigh methods and event handlers
00038   this.expand      = menu_expand;
00039   this.collapse    = menu_collapse;
00040 
00041   this.onclick     = menu_onclick;
00042   this.onmouseout  = menu_onmouseout;
00043   this.onmouseover = menu_onmouseover;
00044   this.onmousedown = menu_onmousedown;
00045 
00046   // default level scope description structure 
00047   this.a_tpl_def = {
00048     'block_top'  : 16,
00049     'block_left' : 16,
00050     'top'        : 20,
00051     'left'       : 4,
00052     'width'      : 120,
00053     'height'     : 22,
00054     'hide_delay' : 0,
00055     'expd_delay' : 0,
00056     'css'        : {
00057       'inner' : '',
00058       'outer' : ''
00059     }
00060   };
00061     
00062   // assign methods and properties required to imulate parent item
00063   this.getprop = function (s_key) {
00064     return this.a_tpl_def[s_key];
00065   };
00066 
00067   this.o_root = this;
00068   this.n_depth = -1;
00069   this.n_x = 0;
00070   this.n_y = 0;
00071 
00072   //  init items recursively
00073   for (n_order = 0; n_order < a_items.length; n_order++)
00074     new menu_item(this, n_order);
00075 
00076   // register self in global collection
00077   A_MENUS[this.n_id] = this;
00078 
00079   // make root level visible
00080   for (var n_order = 0; n_order < this.a_children.length; n_order++)
00081     this.a_children[n_order].e_oelement.style.visibility = 'visible';
00082 }
00083 
00084 // --------------------------------------------------------------------------------
00085 function menu_collapse (n_id) {
00086   // cancel item open delay
00087   clearTimeout(this.o_showtimer);
00088 
00089   // by default collapse to root level
00090   var n_tolevel = (n_id ? this.a_index[n_id].n_depth : 0);
00091     
00092   // hide all items over the level specified
00093   for (n_id = 0; n_id < this.a_index.length; n_id++) {
00094     var o_curritem = this.a_index[n_id];
00095     if (o_curritem.n_depth > n_tolevel && o_curritem.b_visible) {
00096       o_curritem.e_oelement.style.visibility = 'hidden';
00097       o_curritem.b_visible = false;
00098     }
00099   }
00100 
00101   // reset current item if mouse has gone out of items
00102   if (!n_id)
00103     this.o_current = null;
00104 }
00105 
00106 // --------------------------------------------------------------------------------
00107 function menu_expand (n_id) {
00108 
00109   // expand only when mouse is over some menu item
00110   if (this.o_hidetimer)
00111     return;
00112 
00113   // lookup current item
00114   var o_item = this.a_index[n_id];
00115 
00116   // close previously opened items
00117   if (this.o_current && this.o_current.n_depth >= o_item.n_depth)
00118     this.collapse(o_item.n_id);
00119   this.o_current = o_item;
00120 
00121   // exit if there are no children to open
00122   if (!o_item.a_children)
00123     return;
00124 
00125   // show direct child items
00126   for (var n_order = 0; n_order < o_item.a_children.length; n_order++) {
00127     var o_curritem = o_item.a_children[n_order];
00128     o_curritem.e_oelement.style.visibility = 'visible';
00129     o_curritem.b_visible = true;
00130   }
00131 }
00132 
00133 // --------------------------------------------------------------------------------
00134 //
00135 // --------------------------------------------------------------------------------
00136 function menu_onclick (n_id) {
00137   // don't go anywhere if item has no link defined
00138   return Boolean(this.a_index[n_id].a_config[1]);
00139 }
00140 
00141 // --------------------------------------------------------------------------------
00142 function menu_onmouseout (n_id) {
00143 
00144   // lookup new item's object 
00145   var o_item = this.a_index[n_id];
00146 
00147   // apply rollout
00148   o_item.e_oelement.className = o_item.getstyle(0, 0);
00149   o_item.e_ielement.className = o_item.getstyle(1, 0);
00150     
00151   // update status line   
00152   o_item.upstatus(7);
00153 
00154   // run mouseover timer
00155   this.o_hidetimer = setTimeout('A_MENUS['+ this.n_id +'].collapse();',
00156                                 o_item.getprop('hide_delay'));
00157 }
00158 
00159 // --------------------------------------------------------------------------------
00160 function menu_onmouseover (n_id) {
00161 
00162   // cancel mouseoute menu close and item open delay
00163   clearTimeout(this.o_hidetimer);
00164   this.o_hidetimer = null;
00165   clearTimeout(this.o_showtimer);
00166 
00167   // lookup new item's object 
00168   var o_item = this.a_index[n_id];
00169 
00170   // update status line   
00171   o_item.upstatus();
00172 
00173   // apply rollover
00174   o_item.e_oelement.className = o_item.getstyle(0, 1);
00175   o_item.e_ielement.className = o_item.getstyle(1, 1);
00176     
00177   // if onclick open is set then no more actions required
00178   if (o_item.getprop('expd_delay') < 0)
00179     return;
00180 
00181   // run expand timer
00182   this.o_showtimer = setTimeout('A_MENUS['+ this.n_id +'].expand(' + n_id + ');',
00183                                 o_item.getprop('expd_delay'));
00184 
00185 }
00186 
00187 // --------------------------------------------------------------------------------
00188 // called when mouse button is pressed on menu item
00189 // --------------------------------------------------------------------------------
00190 function menu_onmousedown (n_id) {
00191     
00192   // lookup new item's object 
00193   var o_item = this.a_index[n_id];
00194 
00195   // apply mouse down style
00196   o_item.e_oelement.className = o_item.getstyle(0, 2);
00197   o_item.e_ielement.className = o_item.getstyle(1, 2);
00198 
00199   this.expand(n_id);
00200   //  this.items[id].switch_style('onmousedown');
00201 }
00202 
00203 
00204 // --------------------------------------------------------------------------------
00205 // menu item Class
00206 function menu_item (o_parent, n_order) {
00207 
00208   // store parameters passed to the constructor
00209   this.n_depth  = o_parent.n_depth + 1;
00210   this.a_config = o_parent.a_config[n_order + (this.n_depth ? 3 : 0)];
00211 
00212   // return if required parameters are missing
00213   if (!this.a_config) return;
00214 
00215   // store info from parent item
00216   this.o_root    = o_parent.o_root;
00217   this.o_parent  = o_parent;
00218   this.n_order   = n_order;
00219 
00220   // register in global and parent's collections
00221   this.n_id = this.o_root.a_index.length;
00222   this.o_root.a_index[this.n_id] = this;
00223   o_parent.a_children[n_order] = this;
00224 
00225   // calculate item's coordinates
00226   var o_root = this.o_root,
00227     a_tpl  = this.o_root.a_tpl;
00228 
00229   // assign methods
00230   this.getprop  = mitem_getprop;
00231   this.getstyle = mitem_getstyle;
00232   this.upstatus = mitem_upstatus;
00233 
00234   this.n_x = n_order
00235     ? o_parent.a_children[n_order - 1].n_x + this.getprop('left')
00236     : o_parent.n_x + this.getprop('block_left');
00237 
00238   this.n_y = n_order
00239     ? o_parent.a_children[n_order - 1].n_y + this.getprop('top')
00240     : o_parent.n_y + this.getprop('block_top');
00241 
00242   // generate item's HMTL
00243   document.write (
00244                   '<a id="e' + o_root.n_id + '_'
00245                   + this.n_id +'o" class="' + this.getstyle(0, 0) + '" href="' + this.a_config[1] + '"'
00246                   + (this.a_config[2] && this.a_config[2]['tw'] ? ' target="'
00247                      + this.a_config[2]['tw'] + '"' : '') + ' style="position: absolute; top: '
00248                   + this.n_y + 'px; left: ' + this.n_x + 'px; width: '
00249                   + this.getprop('width') + 'px; height: '
00250                   + this.getprop('height') + 'px; visibility: hidden;'
00251                   +' z-index: ' + this.n_depth + ';" '
00252                   + 'onclick="return A_MENUS[' + o_root.n_id + '].onclick('
00253                   + this.n_id + ');" onmouseout="A_MENUS[' + o_root.n_id + '].onmouseout('
00254                   + this.n_id + ');" onmouseover="A_MENUS[' + o_root.n_id + '].onmouseover('
00255                   + this.n_id + ');" onmousedown="A_MENUS[' + o_root.n_id + '].onmousedown('
00256                   + this.n_id + ');"><div  id="e' + o_root.n_id + '_'
00257                   + this.n_id +'i" class="' + this.getstyle(1, 0) + '">'
00258                   + this.a_config[0] + "</div></a>\n"
00259                   );
00260   this.e_ielement = document.getElementById('e' + o_root.n_id + '_' + this.n_id + 'i');
00261   this.e_oelement = document.getElementById('e' + o_root.n_id + '_' + this.n_id + 'o');
00262 
00263   this.b_visible = !this.n_depth;
00264 
00265   // no more initialization if leaf
00266   if (this.a_config.length < 4)
00267     return;
00268 
00269   // node specific methods and properties
00270   this.a_children = [];
00271 
00272   // init downline recursively
00273   for (var n_order = 0; n_order < this.a_config.length - 3; n_order++)
00274     new menu_item(this, n_order);
00275 }
00276 
00277 // --------------------------------------------------------------------------------
00278 // reads property from template file, inherits from parent level if not found
00279 // ------------------------------------------------------------------------------------------
00280 function mitem_getprop (s_key) {
00281 
00282   // check if value is defined for current level
00283   var s_value = null,
00284     a_level = this.o_root.a_tpl[this.n_depth];
00285 
00286   // return value if explicitly defined
00287   if (a_level)
00288     s_value = a_level[s_key];
00289 
00290   // request recursively from parent levels if not defined
00291   return (s_value == null ? this.o_parent.getprop(s_key) : s_value);
00292 }
00293 // --------------------------------------------------------------------------------
00294 // reads property from template file, inherits from parent level if not found
00295 // ------------------------------------------------------------------------------------------
00296 function mitem_getstyle (n_pos, n_state) {
00297 
00298   var a_css = this.getprop('css');
00299   var a_oclass = a_css[n_pos ? 'inner' : 'outer'];
00300 
00301   // same class for all states    
00302   if (typeof(a_oclass) == 'string')
00303     return a_oclass;
00304 
00305   // inherit class from previous state if not explicitly defined
00306   for (var n_currst = n_state; n_currst >= 0; n_currst--)
00307     if (a_oclass[n_currst])
00308       return a_oclass[n_currst];
00309 }
00310 
00311 // ------------------------------------------------------------------------------------------
00312 // updates status bar message of the browser
00313 // ------------------------------------------------------------------------------------------
00314 function mitem_upstatus (b_clear) {
00315   window.setTimeout("window.status=unescape('" + (b_clear
00316                                                   ? ''
00317                                                   : (this.a_config[2] && this.a_config[2]['sb']
00318                                                      ? escape(this.a_config[2]['sb'])
00319                                                      : escape(this.a_config[0]) + (this.a_config[1]
00320                                                                                    ? ' ('+ escape(this.a_config[1]) + ')'
00321                                                                                    : ''))) + "')", 10);
00322 }
00323 
00324 // --------------------------------------------------------------------------------
00325 // that's all folks

Generated on Wed Jan 9 08:27:32 2008 for DokBookWiki by  doxygen 1.5.2