home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / TreeMenu.js < prev    next >
Encoding:
JavaScript  |  2004-03-24  |  20.2 KB  |  641 lines

  1. // +-----------------------------------------------------------------------+
  2. // | Copyright (c) 2002, Richard Heyes, Harald Radi                        |
  3. // | All rights reserved.                                                  |
  4. // |                                                                       |
  5. // | Redistribution and use in source and binary forms, with or without    |
  6. // | modification, are permitted provided that the following conditions    |
  7. // | are met:                                                              |
  8. // |                                                                       |
  9. // | o Redistributions of source code must retain the above copyright      |
  10. // |   notice, this list of conditions and the following disclaimer.       |
  11. // | o Redistributions in binary form must reproduce the above copyright   |
  12. // |   notice, this list of conditions and the following disclaimer in the |
  13. // |   documentation and/or other materials provided with the distribution.| 
  14. // | o The names of the authors may not be used to endorse or promote      |
  15. // |   products derived from this software without specific prior written  |
  16. // |   permission.                                                         |
  17. // |                                                                       |
  18. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
  19. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
  20. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
  21. // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
  22. // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
  23. // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
  24. // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
  25. // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
  26. // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
  27. // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
  28. // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
  29. // |                                                                       |
  30. // +-----------------------------------------------------------------------+
  31. // | Author: Richard Heyes <richard@phpguru.org>                           |
  32. // |         Harald Radi <harald.radi@nme.at>                              |
  33. // +-----------------------------------------------------------------------+
  34. //
  35. // $Id: TreeMenu.js,v 1.1 2003/07/23 18:08:55 meebey Exp $
  36.  
  37.  
  38. /**
  39. * TreeMenu class
  40. */
  41.     function TreeMenu(iconpath, myname, linkTarget, defaultClass, usePersistence, noTopLevelImages)
  42.     {
  43.         // Properties
  44.         this.iconpath         = iconpath;
  45.         this.myname           = myname;
  46.         this.linkTarget       = linkTarget;
  47.         this.defaultClass     = defaultClass;
  48.         this.usePersistence   = usePersistence;
  49.         this.noTopLevelImages = noTopLevelImages;
  50.         this.n                = new Array();
  51.     
  52.         this.nodeRefs       = new Array();
  53.         this.branches       = new Array();
  54.         this.branchStatus   = new Array();
  55.         this.layerRelations = new Array();
  56.         this.childParents   = new Array();
  57.         this.cookieStatuses = new Array();
  58.  
  59.         this.preloadImages();
  60.     }
  61.  
  62. /**
  63. * Adds a node to the tree
  64. */
  65.     TreeMenu.prototype.addItem = function (newNode)
  66.     {
  67.         newIndex = this.n.length;
  68.         this.n[newIndex] = newNode;
  69.         
  70.         return this.n[newIndex];
  71.     }
  72.  
  73. /**
  74. * Preload images hack for Mozilla
  75. */
  76.     TreeMenu.prototype.preloadImages = function ()
  77.     {
  78.         var plustop    = new Image; plustop.src    = this.iconpath + '/plustop.gif';
  79.         var plusbottom = new Image; plusbottom.src = this.iconpath + '/plusbottom.gif';
  80.         var plus       = new Image; plus.src       = this.iconpath + '/plus.gif';
  81.     
  82.         var minustop    = new Image; minustop.src    = this.iconpath + '/minustop.gif';
  83.         var minusbottom = new Image; minusbottom.src = this.iconpath + '/minusbottom.gif';
  84.         var minus       = new Image; minus.src       = this.iconpath + '/minus.gif';
  85.     
  86.         var branchtop    = new Image; branchtop.src    = this.iconpath + '/branchtop.gif';
  87.         var branchbottom = new Image; branchbottom.src = this.iconpath + '/branchbottom.gif';
  88.         var branch       = new Image; branch.src       = this.iconpath + '/branch.gif';
  89.     
  90.         var linebottom = new Image; linebottom.src = this.iconpath + '/linebottom.gif';
  91.         var line       = new Image; line.src       = this.iconpath + '/line.gif';
  92.     }
  93.  
  94. /**
  95. * Main function that draws the menu and assigns it
  96. * to the layer (or document.write()s it)
  97. */
  98.     TreeMenu.prototype.drawMenu = function ()// OPTIONAL ARGS: nodes = [], level = [], prepend = '', expanded = false, visbility = 'inline', parentLayerID = null
  99.     {
  100.         /**
  101.         * Necessary variables
  102.         */
  103.         var output        = '';
  104.         var modifier      = '';
  105.         var layerID       = '';
  106.         var parentLayerID = '';
  107.     
  108.         /**
  109.         * Parse any optional arguments
  110.         */
  111.         var nodes         = arguments[0] ? arguments[0] : this.n
  112.         var level         = arguments[1] ? arguments[1] : [];
  113.         var prepend       = arguments[2] ? arguments[2] : '';
  114.         var expanded      = arguments[3] ? arguments[3] : false;
  115.         var visibility    = arguments[4] ? arguments[4] : 'inline';
  116.         var parentLayerID = arguments[5] ? arguments[5] : null;
  117.     
  118.         var currentlevel  = level.length;
  119.     
  120.         for (var i=0; i<nodes.length; i++) {
  121.         
  122.             level[currentlevel] = i+1;
  123.             layerID = this.myname + '_' + 'node_' + this.implode('_', level);
  124.     
  125.             /**
  126.             * Store this object in the nodeRefs array
  127.             */
  128.             this.nodeRefs[layerID] = nodes[i];
  129.  
  130.             /**
  131.             * Store the child/parent relationship
  132.             */
  133.             this.childParents[layerID] = parentLayerID;
  134.     
  135.             /**
  136.             * Gif modifier
  137.             */
  138.             if (i == 0 && parentLayerID == null) {
  139.                 modifier = nodes.length > 1 ? "top" : 'single';
  140.             } else if(i == (nodes.length-1)) {
  141.                 modifier = "bottom";
  142.             } else {
  143.                 modifier = "";
  144.             }
  145.     
  146.             /**
  147.             * Single root branch is always expanded
  148.             */
  149.             if (!this.doesMenu() || (parentLayerID == null && (nodes.length == 1 || this.noTopLevelImages))) {
  150.                 expanded = true;
  151.     
  152.             } else if (nodes[i].expanded) {
  153.                 expanded = true;
  154.     
  155.             } else {
  156.                 expanded = false;
  157.             }
  158.     
  159.             /**
  160.             * Make sure visibility is correct based on parent status
  161.             */
  162.             visibility =  this.checkParentVisibility(layerID) ? visibility : 'none';
  163.     
  164.             /**
  165.             * Setup branch status and build an indexed array
  166.             * of branch layer ids
  167.             */
  168.             if (nodes[i].n.length > 0) {
  169.                 this.branchStatus[layerID] = expanded;
  170.                 this.branches[this.branches.length] = layerID;
  171.             }
  172.     
  173.             /**
  174.             * Setup toggle relationship
  175.             */
  176.             if (!this.layerRelations[parentLayerID]) {
  177.                 this.layerRelations[parentLayerID] = new Array();
  178.             }
  179.             this.layerRelations[parentLayerID][this.layerRelations[parentLayerID].length] = layerID;
  180.     
  181.             /**
  182.             * Branch images
  183.             */
  184.             var gifname = nodes[i].n.length && this.doesMenu() && nodes[i].isDynamic ? (expanded ? 'minus' : 'plus') : 'branch';
  185.             var iconimg = nodes[i].icon ? this.stringFormat('<img src="{0}/{1}" width="20" height="20" align="top">', this.iconpath, nodes[i].icon) : '';
  186.             
  187.             /**
  188.             * Add event handlers
  189.             */
  190.             var eventHandlers = "";
  191.             for (j in nodes[i].events) {
  192.                 eventHandlers += this.stringFormat('{0}="{1}" ', j, nodes[i].events[j]);
  193.             }
  194.  
  195.             /**
  196.             * Build the html to write to the document
  197.             * IMPORTANT:
  198.             * document.write()ing the string: '<div style="display:...' will screw up nn4.x
  199.             */
  200.             var layerTag  = this.doesMenu() ? this.stringFormat('<div id="{0}" style="display: {1}" class="{2}">', layerID, visibility, (nodes[i].cssClass ? nodes[i].cssClass : this.defaultClass)) : this.stringFormat('<div class="{0}">', '');
  201.             var onMDown   = this.doesMenu() && nodes[i].n.length  && nodes[i].isDynamic ? this.stringFormat('onmousedown="{0}.toggleBranch(\'{1}\', true)" style="cursor: pointer; cursor: hand"', this.myname, layerID) : '';
  202.             var imgTag    = this.stringFormat('<img src="{0}/{1}{2}.gif" width="20" height="20" align="top" border="0" name="img_{3}" {4}>', this.iconpath, gifname, modifier, layerID, onMDown);
  203.             var linkStart = nodes[i].link ? this.stringFormat('<a href="{0}" target="{1}">', nodes[i].link, this.linkTarget) : '';
  204.             var linkEnd   = nodes[i].link ? '</a>' : '';
  205.  
  206.             output = this.stringFormat('{0}<nobr>{1}{2}{3}{4}<span {5}>{6}</span>{7}</nobr><br></div>',
  207.                               layerTag,
  208.                               prepend,
  209.                               parentLayerID == null && (nodes.length == 1 || this.noTopLevelImages) ? '' : imgTag,
  210.                               iconimg,
  211.                               linkStart,
  212.                               eventHandlers,
  213.                               nodes[i].title,
  214.                               linkEnd);
  215.     
  216.             /**
  217.             * Write out the HTML. Uses document.write for speed over layers and
  218.             * innerHTML. This however means no dynamic adding/removing nodes on
  219.             * the client side. This could be conditional I guess if dynamic
  220.             * adding/removing is required.
  221.             */
  222.             document.write(output + "\r\n");
  223.  
  224.             /**
  225.             * Traverse sub nodes ?
  226.             */
  227.             if (nodes[i].n.length) {
  228.                 /**
  229.                 * Determine what to prepend. If there is only one root
  230.                 * node then the prepend to pass to children is nothing.
  231.                 * Otherwise it depends on where we are in the tree.
  232.                 */
  233.                 if (parentLayerID == null && (nodes.length == 1 || this.noTopLevelImages)) {
  234.                     var newPrepend = '';
  235.     
  236.                 } else if (i < (nodes.length - 1)) {
  237.                     var newPrepend = prepend + this.stringFormat('<img src="{0}/line.gif" width="20" height="20" align="top">', this.iconpath);
  238.     
  239.                 } else {
  240.                     var newPrepend = prepend + this.stringFormat('<img src="{0}/linebottom.gif" width="20" height="20" align="top">', this.iconpath);
  241.                 }
  242.     
  243.                 this.drawMenu(nodes[i].n,
  244.                               level,
  245.                               newPrepend,
  246.                               nodes[i].expanded,
  247.                               expanded ? 'inline' : 'none',
  248.                               layerID);
  249.             }
  250.         }
  251.     }
  252.  
  253. /**
  254. * Toggles a branches visible status. Called from resetBranches()
  255. * and also when a +/- graphic is clicked.
  256. */
  257.     TreeMenu.prototype.toggleBranch = function (layerID, updateStatus) // OPTIONAL ARGS: fireEvents = true
  258.     {
  259.         var currentDisplay = this.getLayer(layerID).style.display;
  260.         var newDisplay     = (this.branchStatus[layerID] && currentDisplay == 'inline') ? 'none' : 'inline';
  261.         var fireEvents     = arguments[2] != null ? arguments[2] : true;
  262.     
  263.         for (var i=0; i<this.layerRelations[layerID].length; i++) {
  264.     
  265.             if (this.branchStatus[this.layerRelations[layerID][i]]) {
  266.                 this.toggleBranch(this.layerRelations[layerID][i], false);
  267.             }
  268.     
  269.             this.getLayer(this.layerRelations[layerID][i]).style.display = newDisplay;
  270.         }
  271.     
  272.         if (updateStatus) {
  273.             this.branchStatus[layerID] = !this.branchStatus[layerID];
  274.     
  275.             /**
  276.             * Persistence
  277.             */
  278.             if (this.doesPersistence() && !arguments[2] && this.usePersistence) {
  279.                 this.setExpandedStatusForCookie(layerID, this.branchStatus[layerID]);
  280.             }
  281.  
  282.             /**
  283.             * Fire custom events
  284.             */
  285.             if (fireEvents) {
  286.                 nodeObject = this.nodeRefs[layerID];
  287.     
  288.                 if (nodeObject.ontoggle != null) {
  289.                     eval(nodeObject.ontoggle);
  290.                 }
  291.                 
  292.                 if (newDisplay == 'none' && nodeObject.oncollapse != null) {
  293.                     eval(nodeObject.oncollapse);
  294.                 } else if (newDisplay == 'inline' && nodeObject.onexpand != null){
  295.                     eval(nodeObject.onexpand);
  296.                 }
  297.             }
  298.  
  299.             // Swap image
  300.             this.swapImage(layerID);
  301.         }
  302.     }
  303.  
  304. /**
  305. * Swaps the plus/minus branch images
  306. */
  307.     TreeMenu.prototype.swapImage = function (layerID)
  308.     {
  309.         imgSrc = document.images['img_' + layerID].src;
  310.     
  311.         re = /^(.*)(plus|minus)(bottom|top|single)?.gif$/
  312.         if (matches = imgSrc.match(re)) {
  313.     
  314.             document.images['img_' + layerID].src = this.stringFormat('{0}{1}{2}{3}',
  315.                                                             matches[1],
  316.                                                             matches[2] == 'plus' ? 'minus' : 'plus',
  317.                                                             matches[3] ? matches[3] : '',
  318.                                                             '.gif');
  319.         }
  320.     }
  321.  
  322. /**
  323. * Can the browser handle the dynamic menu?
  324. */
  325.     TreeMenu.prototype.doesMenu = function ()
  326.     {
  327.         return (is_ie4up || is_nav6up || is_gecko);
  328.     }
  329.  
  330. /**
  331. * Can the browser handle save the branch status
  332. */
  333.     TreeMenu.prototype.doesPersistence = function ()
  334.     {
  335.         return (is_ie4up || is_gecko || is_nav6up);
  336.     }
  337.  
  338. /**
  339. * Returns the appropriate layer accessor
  340. */
  341.     TreeMenu.prototype.getLayer = function (layerID)
  342.     {
  343.         if (is_ie4) {
  344.             return document.all(layerID);
  345.     
  346.         } else if (document.getElementById(layerID)) {
  347.             return document.getElementById(layerID);
  348.     
  349.         } else if (document.all(layerID)) {
  350.             return document.all(layerID);
  351.         }
  352.     }
  353.  
  354. /**
  355. * Save the status of the layer
  356. */
  357.     TreeMenu.prototype.setExpandedStatusForCookie = function (layerID, expanded)
  358.     {
  359.         this.cookieStatuses[layerID] = expanded;
  360.         this.saveCookie();
  361.     }
  362.  
  363. /**
  364. * Load the status of the layer
  365. */
  366.     TreeMenu.prototype.getExpandedStatusFromCookie = function (layerID)
  367.     {
  368.         if (this.cookieStatuses[layerID]) {
  369.             return this.cookieStatuses[layerID];
  370.         }
  371.  
  372.         return false;
  373.     }
  374.  
  375. /**
  376. * Saves the cookie that holds which branches are expanded.
  377. * Only saves the details of the branches which are expanded.
  378. */
  379.     TreeMenu.prototype.saveCookie = function ()
  380.     {
  381.         var cookieString = new Array();
  382.  
  383.         for (var i in this.cookieStatuses) {
  384.             if (this.cookieStatuses[i] == true) {
  385.                 cookieString[cookieString.length] = i;
  386.             }
  387.         }
  388.         
  389.         document.cookie = 'TreeMenuBranchStatus=' + cookieString.join(':');
  390.     }
  391.  
  392. /**
  393. * Reads cookie parses it for status info and
  394. * stores that info in the class member.
  395. */
  396.     TreeMenu.prototype.loadCookie = function ()
  397.     {
  398.         var cookie = document.cookie.split('; ');
  399.  
  400.         for (var i=0; i < cookie.length; i++) {
  401.             var crumb = cookie[i].split('=');
  402.             if ('TreeMenuBranchStatus' == crumb[0] && crumb[1]) {
  403.                 var expandedBranches = crumb[1].split(':');
  404.                 for (var j=0; j<expandedBranches.length; j++) {
  405.                     this.cookieStatuses[expandedBranches[j]] = true;
  406.                 }
  407.             }
  408.         }
  409.     }
  410.  
  411. /**
  412. * Reset branch status
  413. */
  414.     TreeMenu.prototype.resetBranches = function ()
  415.     {
  416.         if (!this.doesPersistence()) {
  417.             return false;
  418.         }
  419.  
  420.         this.loadCookie();
  421.  
  422.         for (var i=0; i<this.branches.length; i++) {
  423.             var status = this.getExpandedStatusFromCookie(this.branches[i]);
  424.             // Only update if it's supposed to be expanded and it's not already
  425.             if (status == true && this.branchStatus[this.branches[i]] != true) {
  426.                 if (this.checkParentVisibility(this.branches[i])) {
  427.                     this.toggleBranch(this.branches[i], true, false);
  428.                 } else {
  429.                     this.branchStatus[this.branches[i]] = true;
  430.                     this.swapImage(this.branches[i]);
  431.                 }
  432.             }
  433.         }
  434.     }
  435.  
  436. /**
  437. * Checks whether a branch should be open 
  438. * or not based on its parents' status
  439. */
  440.     TreeMenu.prototype.checkParentVisibility = function (layerID)
  441.     {
  442.         if (this.in_array(this.childParents[layerID], this.branches)
  443.             && this.branchStatus[this.childParents[layerID]]
  444.             && this.checkParentVisibility(this.childParents[layerID]) ) {
  445.             
  446.             return true;
  447.     
  448.         } else if (this.childParents[layerID] == null) {
  449.             return true;
  450.         }
  451.         
  452.         return false;
  453.     }
  454.  
  455. /**
  456. * New C# style string formatter
  457. */
  458.     TreeMenu.prototype.stringFormat = function (strInput)
  459.     {
  460.         var idx = 0;
  461.     
  462.         for (var i=1; i<arguments.length; i++) {
  463.             while ((idx = strInput.indexOf('{' + (i - 1) + '}', idx)) != -1) {
  464.                 strInput = strInput.substring(0, idx) + arguments[i] + strInput.substr(idx + 3);
  465.             }
  466.         }
  467.         
  468.         return strInput;
  469.     }
  470.  
  471. /**
  472. * Also much adored, the PHP implode() function
  473. */
  474.     TreeMenu.prototype.implode = function (seperator, input)
  475.     {
  476.         var output = '';
  477.     
  478.         for (var i=0; i<input.length; i++) {
  479.             if (i == 0) {
  480.                 output += input[i];
  481.             } else {
  482.                 output += seperator + input[i];
  483.             }
  484.         }
  485.         
  486.         return output;
  487.     }
  488.  
  489. /**
  490. * Aah, all the old favourites are coming out...
  491. */
  492.     TreeMenu.prototype.in_array = function (item, arr)
  493.     {
  494.         for (var i=0; i<arr.length; i++) {
  495.             if (arr[i] == item) {
  496.                 return true;
  497.             }
  498.         }
  499.     
  500.         return false;
  501.     }
  502.  
  503. /**
  504. * TreeNode Class
  505. */
  506.     function TreeNode(title, icon, link, expanded, isDynamic, cssClass)
  507.     {
  508.         this.title      = title;
  509.         this.icon       = icon;
  510.         this.link       = link;
  511.         this.expanded   = expanded;
  512.         this.isDynamic  = isDynamic;
  513.         this.cssClass   = cssClass;
  514.         this.n          = new Array();
  515.         this.events     = new Array();
  516.         this.handlers   = null;
  517.         this.oncollapse = null;
  518.         this.onexpand   = null;
  519.         this.ontoggle   = null;
  520.     }
  521.  
  522. /**
  523. * Adds a node to an already existing node
  524. */
  525.     TreeNode.prototype.addItem = function (newNode)
  526.     {
  527.         newIndex = this.n.length;
  528.         this.n[newIndex] = newNode;
  529.         
  530.         return this.n[newIndex];
  531.     }
  532.  
  533. /**
  534. * Sets an event for this particular node
  535. */
  536.     TreeNode.prototype.setEvent = function (eventName, eventHandler)
  537.     {
  538.         switch (eventName.toLowerCase()) {
  539.             case 'onexpand':
  540.                 this.onexpand = eventHandler;
  541.                 break;
  542.  
  543.             case 'oncollapse':
  544.                 this.oncollapse = eventHandler;
  545.                 break;
  546.  
  547.             case 'ontoggle':
  548.                 this.ontoggle = eventHandler;
  549.                 break;
  550.  
  551.             default:
  552.                 this.events[eventName] = eventHandler;
  553.         }
  554.     }
  555.  
  556. /**
  557. * That's the end of the tree classes. What follows is
  558. * the browser detection code.
  559. */
  560.     
  561.  
  562. //<!--
  563. // Ultimate client-side JavaScript client sniff. Version 3.03
  564. // (C) Netscape Communications 1999-2001.  Permission granted to reuse and distribute.
  565. // Revised 17 May 99 to add is_nav5up and is_ie5up (see below).
  566. // Revised 20 Dec 00 to add is_gecko and change is_nav5up to is_nav6up
  567. //                      also added support for IE5.5 Opera4&5 HotJava3 AOLTV
  568. // Revised 22 Feb 01 to correct Javascript Detection for IE 5.x, Opera 4, 
  569. //                      correct Opera 5 detection
  570. //                      add support for winME and win2k
  571. //                      synch with browser-type-oo.js
  572. // Revised 26 Mar 01 to correct Opera detection
  573. // Revised 02 Oct 01 to add IE6 detection
  574.  
  575. // Everything you always wanted to know about your JavaScript client
  576. // but were afraid to ask. Creates "is_" variables indicating:
  577. // (1) browser vendor:
  578. //     is_nav, is_ie, is_opera, is_hotjava, is_webtv, is_TVNavigator, is_AOLTV
  579. // (2) browser version number:
  580. //     is_major (integer indicating major version number: 2, 3, 4 ...)
  581. //     is_minor (float   indicating full  version number: 2.02, 3.01, 4.04 ...)
  582. // (3) browser vendor AND major version number
  583. //     is_nav2, is_nav3, is_nav4, is_nav4up, is_nav6, is_nav6up, is_gecko, is_ie3,
  584. //     is_ie4, is_ie4up, is_ie5, is_ie5up, is_ie5_5, is_ie5_5up, is_ie6, is_ie6up, is_hotjava3, is_hotjava3up,
  585. //     is_opera2, is_opera3, is_opera4, is_opera5, is_opera5up
  586. // (4) JavaScript version number:
  587. //     is_js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
  588. // (5) OS platform and version:
  589. //     is_win, is_win16, is_win32, is_win31, is_win95, is_winnt, is_win98, is_winme, is_win2k
  590. //     is_os2
  591. //     is_mac, is_mac68k, is_macppc
  592. //     is_unix
  593. //     is_sun, is_sun4, is_sun5, is_suni86
  594. //     is_irix, is_irix5, is_irix6
  595. //     is_hpux, is_hpux9, is_hpux10
  596. //     is_aix, is_aix1, is_aix2, is_aix3, is_aix4
  597. //     is_linux, is_sco, is_unixware, is_mpras, is_reliant
  598. //     is_dec, is_sinix, is_freebsd, is_bsd
  599. //     is_vms
  600. //
  601. // See http://www.it97.de/JavaScript/JS_tutorial/bstat/navobj.html and
  602. // http://www.it97.de/JavaScript/JS_tutorial/bstat/Browseraol.html
  603. // for detailed lists of userAgent strings.
  604. //
  605. // Note: you don't want your Nav4 or IE4 code to "turn off" or
  606. // stop working when new versions of browsers are released, so
  607. // in conditional code forks, use is_ie5up ("IE 5.0 or greater") 
  608. // is_opera5up ("Opera 5.0 or greater") instead of is_ie5 or is_opera5
  609. // to check version in code which you want to work on future
  610. // versions.
  611.  
  612. /**
  613. * Severly curtailed all this as only certain elements
  614. * are required by TreeMenu, specifically:
  615. *  o is_ie4up
  616. *  o is_nav6up
  617. *  o is_gecko
  618. */
  619.  
  620.     // convert all characters to lowercase to simplify testing
  621.     var agt=navigator.userAgent.toLowerCase();
  622.  
  623.     // *** BROWSER VERSION ***
  624.     // Note: On IE5, these return 4, so use is_ie5up to detect IE5.
  625.     var is_major = parseInt(navigator.appVersion);
  626.     var is_minor = parseFloat(navigator.appVersion);
  627.  
  628.     // Note: Opera and WebTV spoof Navigator.  We do strict client detection.
  629.     // If you want to allow spoofing, take out the tests for opera and webtv.
  630.     var is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
  631.                 && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
  632.                 && (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
  633.     var is_nav6up = (is_nav && (is_major >= 5));
  634.     var is_gecko = (agt.indexOf('gecko') != -1);
  635.  
  636.  
  637.     var is_ie     = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
  638.     var is_ie4    = (is_ie && (is_major == 4) && (agt.indexOf("msie 4")!=-1) );
  639.     var is_ie4up  = (is_ie && (is_major >= 4));
  640. //--> end hide JavaScript
  641.