var isFarsi = true; // Globals var _cmIDCount = 0; var _cmIDName = 'cmSubMenuID'; // for creating submenu id var _cmTimeOut = null; // how long the menu would stay var _cmCurrentItem = null; // the current menu item being selected; var _cmNoAction = new Object (); // indicate that the item cannot be hovered. var _cmNoClick = new Object (); // similar to _cmNoAction but does not respond to mouseup/mousedown events var _cmSplit = new Object (); // indicate that the item is a menu split var _cmItemList = new Array (); // a simple list of items // default node properties var _cmNodeProperties = { // main menu display attributes // // Note. When the menu bar is horizontal, // mainFolderLeft and mainFolderRight are // put in . When the menu // bar is vertical, they would be put in // a separate TD cell. // HTML code to the left of the folder item mainFolderLeft: '', // HTML code to the right of the folder item mainFolderRight: '', // HTML code to the left of the regular item mainItemLeft: '', // HTML code to the right of the regular item mainItemRight: '', // sub menu display attributes // HTML code to the left of the folder item folderLeft: '', // HTML code to the right of the folder item folderRight: '', // HTML code to the left of the regular item itemLeft: '', // HTML code to the right of the regular item itemRight: '', // cell spacing for main menu mainSpacing: 0, // cell spacing for sub menus subSpacing: 0, // auto disappear time for submenus in milli-seconds delay: 800, // act on click to open sub menu // not yet implemented // 0 : use default behavior // 1 : hover open in all cases // 2 : click on main, hover on sub // 3 : click open in all cases clickOpen: 1 }; ////////////////////////////////////////////////////////////////////// // // Drawing Functions and Utility Functions // ////////////////////////////////////////////////////////////////////// // // produce a new unique id // function cmNewID () { return _cmIDName + (++_cmIDCount); } // // return the property string for the menu item // function cmActionItem (item, prefix, isMain, idSub, orient, nodeProperties) { var clickOpen = _cmNodeProperties.clickOpen; if (nodeProperties.clickOpen) clickOpen = nodeProperties.clickOpen; // var index = _cmItemList.push (item) - 1; _cmItemList[_cmItemList.length] = item; var index = _cmItemList.length - 1; idSub = (!idSub) ? 'null' : ('\'' + idSub + '\''); orient = '\'' + orient + '\''; prefix = '\'' + prefix + '\''; var onClick = (clickOpen == 3) || (clickOpen == 2 && isMain); var returnStr; if (onClick) returnStr = ' onmouseover="cmItemMouseOver (this,' + prefix + ',' + isMain + ',' + idSub + ',' + index + ')" onmousedown="cmItemMouseDownOpenSub (this,' + index + ',' + prefix + ',' + orient + ',' + idSub + ')"'; else returnStr = ' onmouseover="cmItemMouseOverOpenSub (this,' + prefix + ',' + isMain + ',' + idSub + ',' + orient + ',' + index + ')" onmousedown="cmItemMouseDown (this,' + index + ')"'; return returnStr + ' onmouseout="cmItemMouseOut (this,' + nodeProperties.delay + ')" onmouseup="cmItemMouseUp (this,' + index + ')"'; } // // this one is used by _cmNoClick to only take care of onmouseover and onmouseout // events which are associated with menu but not actions associated with menu clicking/closing // function cmNoClickItem (item, prefix, isMain, idSub, orient, nodeProperties) { // var index = _cmItemList.push (item) - 1; _cmItemList[_cmItemList.length] = item; var index = _cmItemList.length - 1; idSub = (!idSub) ? 'null' : ('\'' + idSub + '\''); orient = '\'' + orient + '\''; prefix = '\'' + prefix + '\''; return ' onmouseover="cmItemMouseOver (this,' + prefix + ',' + isMain + ',' + idSub + ',' + index + ')" onmouseout="cmItemMouseOut (this,' + nodeProperties.delay + ')"'; } function cmNoActionItem (item, prefix) { return item[1]; } function cmSplitItem (prefix, isMain, vertical) { var classStr = 'cm' + prefix; if (isMain) { classStr += 'Main'; if (vertical) classStr += 'HSplit'; else classStr += 'VSplit'; } else classStr += 'HSplit'; return eval (classStr); } // // draw the sub menu recursively // function cmDrawSubMenu (subMenu, prefix, id, orient, nodeProperties) { var str = '
'; var strSub = ''; var item; var idSub; var hasChild; var i; var classStr; for (i = 5; i < subMenu.length; ++i) { item = subMenu[i]; if (!item) continue; if (item == _cmSplit) item = cmSplitItem (prefix, 0, true); hasChild = (item.length > 5); idSub = hasChild ? cmNewID () : null; str += ''; if (item[0] != null) str += item[0]; else str += hasChild ? nodeProperties.folderLeft : nodeProperties.itemLeft; str += ''; } str += '
' + item[1]; str += ''; if (hasChild) { str += nodeProperties.folderRight; strSub += cmDrawSubMenu (item, prefix, idSub, orient, nodeProperties); } else str += nodeProperties.itemRight; str += '
' + strSub; return str; } // // The function that builds the menu inside the specified element id. // // @param id id of the element // orient orientation of the menu in [hv][ab][lr] format // menu the menu object to be drawn // nodeProperties properties for each menu node // function cmDraw (id, menu, orient, nodeProperties, prefix) { return cmDraw (false,id, menu, orient, nodeProperties, prefix); } function cmDraw (Farsi,id, menu, orient, nodeProperties, prefix) { //isFarsi = Farsi; var obj = cmGetObject (id); if (!nodeProperties) nodeProperties = _cmNodeProperties; if (!prefix) prefix = ''; var str = ''; var strSub = ''; if (!orient) orient = 'hbr'; var orientStr = String (orient); var orientSub; var vertical; // draw the main menu items if (orientStr.charAt (0) == 'h') { // horizontal menu orientSub = 'v' + orientStr.substr (1, 2); str += ''; vertical = false; } else { // vertical menu orientSub = 'v' + orientStr.substr (1, 2); vertical = true; } var i; var item; var idSub; var hasChild; var classStr; for (i = 0; i < menu.length; ++i) { item = menu[i]; if (!item) continue; str += vertical ? ' 5); idSub = hasChild ? cmNewID () : null; str += cmActionItem (item, prefix, 1, idSub, orient, nodeProperties) + '>'; if (item == _cmSplit) item = cmSplitItem (prefix, 1, vertical); if (item[0] == _cmNoAction || item[0] == _cmNoClick) { str += cmNoActionItem (item, prefix); str += vertical? '' : ''; continue; } classStr = prefix + 'Main' + (hasChild ? 'Folder' : 'Item'); str += vertical ? ''; str += (item[0] == null) ? (hasChild ? nodeProperties.mainFolderLeft : nodeProperties.mainItemLeft) : item[0]; str += vertical ? '' : ''; str += vertical ? ''; str += item[1]; str += vertical ? '' : ''; str += vertical ? ''; str += hasChild ? nodeProperties.mainFolderRight : nodeProperties.mainItemRight; str += vertical ? '' : ''; str += vertical ? '' : ''; if (hasChild) strSub += cmDrawSubMenu (item, prefix, idSub, orientSub, nodeProperties); } if (!vertical) str += ''; str += '
' + strSub; obj.innerHTML = str; //document.write ("" + str + ""); } // // The function builds the menu inside the specified element id. // // This function is similar to cmDraw except that menu is taken from HTML node // rather a javascript tree. This feature allows links to be scanned by search // bots. // // This function basically converts HTML node to a javascript tree, and then calls // cmDraw to draw the actual menu, replacing the hidden menu tree. // // Format: // // function cmDrawFromText (id, orient, nodeProperties, prefix) { var domMenu = cmGetObject (id); var menu = null; for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling) { if (!currentDomItem.tagName || currentDomItem.tagName.toLowerCase () != 'ul') continue; menu = cmDrawFromTextSubMenu (currentDomItem); break; } if (menu) cmDraw (id, menu, orient, nodeProperties, prefix); } // // a recursive function that build menu tree structure // function cmDrawFromTextSubMenu (domMenu) { var items = new Array (); for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling) { if (!currentDomItem.tagName || currentDomItem.tagName.toLowerCase () != 'li') continue; if (currentDomItem.firstChild == null) { items[items.length] = _cmSplit; continue; } var item = new Array (); var currentItem = currentDomItem.firstChild; for (; currentItem; currentItem = currentItem.nextSibling) { // scan for span tag if (!currentItem.tagName || currentItem.tagName.toLowerCase () != 'span') continue; if (!currentItem.firstChild) item[0] = null; else item[0] = currentItem.innerHTML; break; } if (!currentItem) continue; for (; currentItem; currentItem = currentItem.nextSibling) { // scan for span tag if (!currentItem.tagName || currentItem.tagName.toLowerCase () != 'a') continue; item[1] = currentItem.innerHTML; item[2] = currentItem.href; item[3] = currentItem.target; item[4] = currentItem.title; if (item[4] == '') item[4] = null; break; } for (; currentItem; currentItem = currentItem.nextSibling) { // scan for span tag if (!currentItem.tagName || currentItem.tagName.toLowerCase () != 'ul') continue; var subMenuItems = cmDrawFromTextSubMenu (currentItem); for (i = 0; i < subMenuItems.length; ++i) item[i + 5] = subMenuItems[i]; break; } items[items.length] = item; } return items; } ////////////////////////////////////////////////////////////////////// // // Mouse Event Handling Functions // ////////////////////////////////////////////////////////////////////// // // action should be taken for mouse moving in to the menu item // // Here we just do things concerning this menu item, w/o opening sub menus. // function cmItemMouseOver (obj, prefix, isMain, idSub, index) { clearTimeout (_cmTimeOut); if (!obj.cmPrefix) { obj.cmPrefix = prefix; obj.cmIsMain = isMain; } var thisMenu = cmGetThisMenu (obj, prefix); // insert obj into cmItems if cmItems doesn't have obj if (!thisMenu.cmItems) thisMenu.cmItems = new Array (); var i; for (i = 0; i < thisMenu.cmItems.length; ++i) { if (thisMenu.cmItems[i] == obj) break; } if (i == thisMenu.cmItems.length) { //thisMenu.cmItems.push (obj); thisMenu.cmItems[i] = obj; } // hide the previous submenu that is not this branch if (_cmCurrentItem) { // occationally, we get this case when user // move the mouse slowly to the border if (_cmCurrentItem == obj || _cmCurrentItem == thisMenu) { var item = _cmItemList[index]; cmSetStatus (item); return; } var thatPrefix = _cmCurrentItem.cmPrefix; var thatMenu = cmGetThisMenu (_cmCurrentItem, thatPrefix); if (thatMenu != thisMenu.cmParentMenu) { if (_cmCurrentItem.cmIsMain) _cmCurrentItem.className = thatPrefix + 'MainItem'; else _cmCurrentItem.className = thatPrefix + 'MenuItem'; if (thatMenu.id != idSub) cmHideMenu (thatMenu, thisMenu, thatPrefix); } } // okay, set the current menu to this obj _cmCurrentItem = obj; // just in case, reset all items in this menu to MenuItem cmResetMenu (thisMenu, prefix); var item = _cmItemList[index]; var isDefaultItem = cmIsDefaultItem (item); if (isDefaultItem) { if (isMain) if(isFarsi) obj.className = prefix + 'MainItemHover_ir'; else obj.className = prefix + 'MainItemHover_en'; else obj.className = prefix + 'MenuItemHover'; } cmSetStatus (item); } // // action should be taken for mouse moving in to the menu item // // This function also opens sub menu // function cmItemMouseOverOpenSub (obj, prefix, isMain, idSub, orient, index) { cmItemMouseOver (obj, prefix, isMain, idSub, index); if (idSub) { var subMenu = cmGetObject (idSub); cmShowSubMenu (obj, prefix, subMenu, orient); } } // // action should be taken for mouse moving out of the menu item // function cmItemMouseOut (obj, delayTime) { if (!delayTime) delayTime = _cmNodeProperties.delay; _cmTimeOut = window.setTimeout ('cmHideMenuTime ()', delayTime); window.defaultStatus = ''; } // // action should be taken for mouse button down at a menu item // function cmItemMouseDown (obj, index) { if (cmIsDefaultItem (_cmItemList[index])) { if (obj.cmIsMain) obj.className = obj.cmPrefix + 'MainItemActive'; else obj.className = obj.cmPrefix + 'MenuItemActive'; } } // // action should be taken for mouse button down at a menu item // this is one also opens submenu if needed // function cmItemMouseDownOpenSub (obj, index, prefix, orient, idSub) { cmItemMouseDown (obj, index); if (idSub) { var subMenu = cmGetObject (idSub); cmShowSubMenu (obj, prefix, subMenu, orient); } } // // action should be taken for mouse button up at a menu item // function cmItemMouseUp (obj, index) { var item = _cmItemList[index]; var link = null, target = '_self'; if (item.length > 2) link = item[2]; if (item.length > 3 && item[3]) target = item[3]; if (link != null) { window.open (link, target); } var prefix = obj.cmPrefix; var thisMenu = cmGetThisMenu (obj, prefix); var hasChild = (item.length > 5); if (!hasChild) { if (cmIsDefaultItem (item)) { if (obj.cmIsMain) obj.className = prefix + 'MainItem'; else obj.className = prefix + 'MenuItem'; } cmHideMenu (thisMenu, null, prefix); } else { if (cmIsDefaultItem (item)) { if (obj.cmIsMain) obj.className = prefix + 'MainItemHover'; else obj.className = prefix + 'MenuItemHover'; } } } ////////////////////////////////////////////////////////////////////// // // Mouse Event Support Utility Functions // ////////////////////////////////////////////////////////////////////// // // move submenu to the appropriate location // // @param obj the menu item that opens up the subMenu // subMenu the sub menu to be shown // orient the orientation of the subMenu // function cmMoveSubMenu (obj, subMenu, orient) { var mode = String (orient); var p = subMenu.offsetParent; var subMenuWidth = cmGetWidth (subMenu); var horiz = cmGetHorizontalAlign (obj, mode, p, subMenuWidth); if (mode.charAt (0) == 'h') { if (mode.charAt (1) == 'b') subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj)) + 'px'; else subMenu.style.top = (cmGetYAt (obj, p) - cmGetHeight (subMenu)) + 'px'; if (horiz == 'r') subMenu.style.left = (cmGetXAt (obj, p)) + 'px'; else subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) - subMenuWidth) + 'px'; } else { if (horiz == 'r') { if(isFarsi) subMenu.style.left = (cmGetXAt (obj, p) - subMenuWidth + 50) + 'px'; else subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) - 20) + 'px'; } else { if(isFarsi) subMenu.style.left = (cmGetXAt (obj, p) - subMenuWidth + 50) + 'px'; else subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) - 20) + 'px'; } if (mode.charAt (1) == 'b') subMenu.style.top = (cmGetYAt (obj, p)) + 'px'; else subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj) - cmGetHeight (subMenu)) + 'px'; } } // // automatically re-adjust the menu position based on available screen size. // function cmGetHorizontalAlign (obj, mode, p, subMenuWidth) { var horiz = mode.charAt (2); if (!(document.body)) return horiz; var body = document.body; var browserLeft; var browserRight; if (window.innerWidth) { // DOM window attributes browserLeft = window.pageXOffset; browserRight = window.innerWidth + browserLeft; } else if (body.clientWidth) { // IE attributes browserLeft = body.clientLeft; browserRight = body.clientWidth + browserLeft; } else return horiz; if (mode.charAt (0) == 'h') { if (horiz == 'r' && (cmGetXAt (obj) + subMenuWidth) > browserRight) horiz = 'l'; if (horiz == 'l' && (cmGetXAt (obj) + cmGetWidth (obj) - subMenuWidth) < browserLeft) horiz = 'r'; return horiz; } else { if (horiz == 'r' && (cmGetXAt (obj, p) + cmGetWidth (obj) + subMenuWidth) > browserRight) horiz = 'l'; if (horiz == 'l' && (cmGetXAt (obj, p) - subMenuWidth) < browserLeft) horiz = 'r'; return horiz; } } // // show the subMenu w/ specified orientation // also move it to the correct coordinates // // @param obj the menu item that opens up the subMenu // subMenu the sub menu to be shown // orient the orientation of the subMenu // function cmShowSubMenu (obj, prefix, subMenu, orient) { if (!subMenu.cmParentMenu) { // establish the tree w/ back edge var thisMenu = cmGetThisMenu (obj, prefix); subMenu.cmParentMenu = thisMenu; if (!thisMenu.cmSubMenu) thisMenu.cmSubMenu = new Array (); //thisMenu.cmSubMenu.push (subMenu); thisMenu.cmSubMenu[thisMenu.cmSubMenu.length] = subMenu; } // position the sub menu cmMoveSubMenu (obj, subMenu, orient); subMenu.style.visibility = 'visible'; // // On IE, controls such as SELECT, OBJECT, IFRAME (before 5.5) // are window based controls. So, if the sub menu and these // controls overlap, sub menu would be hidden behind them. Thus // one needs to turn the visibility of these controls off when the // sub menu is showing, and turn their visibility back on // when the sub menu is hiding. // if (document.all) // it is IE { /* part of Felix Zaslavskiy's fix on hiding controls not really sure if this part is necessary, but shouldn't hurt. */ if (!subMenu.cmOverlap) subMenu.cmOverlap = new Array (); /*@cc_on @*/ /*@if (@_jscript_version >= 5.5) @else @*/ cmHideControl ("IFRAME", subMenu); /*@end @*/ cmHideControl ("SELECT", subMenu); cmHideControl ("OBJECT", subMenu); } } // // reset all the menu items to class MenuItem in thisMenu // function cmResetMenu (thisMenu, prefix) { if (thisMenu.cmItems) { var i; var str; var items = thisMenu.cmItems; for (i = 0; i < items.length; ++i) { if (items[i].cmIsMain) str = prefix + 'MainItem'; else str = prefix + 'MenuItem'; if (items[i].className != str) items[i].className = str; } } } // // called by the timer to hide the menu // function cmHideMenuTime () { if (_cmCurrentItem) { var prefix = _cmCurrentItem.cmPrefix; cmHideMenu (cmGetThisMenu (_cmCurrentItem, prefix), null, prefix); _cmCurrentItem = null; } } // // hide thisMenu, children of thisMenu, as well as the ancestor // of thisMenu until currentMenu is encountered. currentMenu // will not be hidden // function cmHideMenu (thisMenu, currentMenu, prefix) { var str = prefix + 'SubMenu'; // hide the down stream menus if (thisMenu.cmSubMenu) { var i; for (i = 0; i < thisMenu.cmSubMenu.length; ++i) { cmHideSubMenu (thisMenu.cmSubMenu[i], prefix); } } // hide the upstream menus while (thisMenu && thisMenu != currentMenu) { cmResetMenu (thisMenu, prefix); if (thisMenu.className == str) { thisMenu.style.visibility = 'hidden'; cmShowControl (thisMenu); } else break; thisMenu = cmGetThisMenu (thisMenu.cmParentMenu, prefix); } } // // hide thisMenu as well as its sub menus if thisMenu is not // already hidden // function cmHideSubMenu (thisMenu, prefix) { if (thisMenu.style.visibility == 'hidden') return; if (thisMenu.cmSubMenu) { var i; for (i = 0; i < thisMenu.cmSubMenu.length; ++i) { cmHideSubMenu (thisMenu.cmSubMenu[i], prefix); } } cmResetMenu (thisMenu, prefix); thisMenu.style.visibility = 'hidden'; cmShowControl (thisMenu); } // // hide a control such as IFRAME // function cmHideControl (tagName, subMenu) { var x = cmGetX (subMenu); var y = cmGetY (subMenu); var w = subMenu.offsetWidth; var h = subMenu.offsetHeight; var i; for (i = 0; i < document.all.tags(tagName).length; ++i) { var obj = document.all.tags(tagName)[i]; if (!obj || !obj.offsetParent) continue; // check if the object and the subMenu overlap var ox = cmGetX (obj); var oy = cmGetY (obj); var ow = obj.offsetWidth; var oh = obj.offsetHeight; if (ox > (x + w) || (ox + ow) < x) continue; if (oy > (y + h) || (oy + oh) < y) continue; // if object is already made hidden by a different // submenu then we dont want to put it on overlap list of // of a submenu a second time. // - bug fixed by Felix Zaslavskiy if(obj.style.visibility == "hidden") continue; //subMenu.cmOverlap.push (obj); subMenu.cmOverlap[subMenu.cmOverlap.length] = obj; obj.style.visibility = "hidden"; } } // // show the control hidden by the subMenu // function cmShowControl (subMenu) { if (subMenu.cmOverlap) { var i; for (i = 0; i < subMenu.cmOverlap.length; ++i) subMenu.cmOverlap[i].style.visibility = ""; } subMenu.cmOverlap = null; } // // returns the main menu or the submenu table where this obj (menu item) // is in // function cmGetThisMenu (obj, prefix) { var str1 = prefix + 'SubMenu'; var str2 = prefix + 'Menu'; while (obj) { if (obj.className == str1 || obj.className == str2) return obj; obj = obj.parentNode; } return null; } // // return true if this item is handled using default handlers // function cmIsDefaultItem (item) { if (item == _cmSplit || item[0] == _cmNoAction || item[0] == _cmNoClick) return false; return true; } // // returns the object baring the id // function cmGetObject (id) { if (document.all) return document.all[id]; return document.getElementById (id); } // // functions that obtain the width of an HTML element. // function cmGetWidth (obj) { var width = obj.offsetWidth; if (width > 0 || !cmIsTRNode (obj)) return width; if (!obj.firstChild) return 0; // use TABLE's length can cause an extra pixel gap //return obj.parentNode.parentNode.offsetWidth; // use the left and right child instead return obj.lastChild.offsetLeft - obj.firstChild.offsetLeft + cmGetWidth (obj.lastChild); } // // functions that obtain the height of an HTML element. // function cmGetHeight (obj) { var height = obj.offsetHeight; if (height > 0 || !cmIsTRNode (obj)) return height; if (!obj.firstChild) return 0; // use the first child's height return obj.firstChild.offsetHeight; } // // functions that obtain the coordinates of an HTML element // function cmGetX (obj) { var x = 0; do { x += obj.offsetLeft; obj = obj.offsetParent; } while (obj); return x; } function cmGetXAt (obj, elm) { var x = 0; while (obj && obj != elm) { x += obj.offsetLeft; obj = obj.offsetParent; } if (obj == elm) return x; return x - cmGetX (elm); } function cmGetY (obj) { var y = 0; do { y += obj.offsetTop; obj = obj.offsetParent; } while (obj); return y; } function cmIsTRNode (obj) { var tagName = obj.tagName; return tagName == "TR" || tagName == "tr" || tagName == "Tr" || tagName == "tR"; } // // get the Y position of the object. In case of TR element though, // we attempt to adjust the value. // function cmGetYAt (obj, elm) { var y = 0; if (!obj.offsetHeight && cmIsTRNode (obj)) { var firstTR = obj.parentNode.firstChild; obj = obj.firstChild; y -= firstTR.firstChild.offsetTop; } while (obj && obj != elm) { y += obj.offsetTop; obj = obj.offsetParent; } if (obj == elm) return y; return y - cmGetY (elm); } // // extract description from the menu item and set the status text // @param item the menu item // function cmSetStatus (item) { var descript = ''; if (item.length > 4) descript = (item[4] != null) ? item[4] : (item[2] ? item[2] : descript); else if (item.length > 2) descript = (item[2] ? item[2] : descript); window.defaultStatus = descript; } // // debug function, ignore :) // function cmGetProperties (obj) { if (obj == undefined) return 'undefined'; if (obj == null) return 'null'; var msg = obj + ':\n'; var i; for (i in obj) msg += i + ' = ' + obj[i] + '; '; return msg; }