update to TreeMenu 1.1.9
authorchriskl <chriskl>
Mon, 2 Feb 2004 06:32:18 +0000 (06:32 +0000)
committerchriskl <chriskl>
Mon, 2 Feb 2004 06:32:18 +0000 (06:32 +0000)
classes/HTML_TreeMenu/TreeMenu.js
classes/HTML_TreeMenu/TreeMenu.php

index 1986696cd6a348fb5d2ef68d0bf9d9fe1981aa55..7a7d73d53db35cc85f3081a8e33f413bc038764b 100755 (executable)
 // |         Harald Radi <harald.radi@nme.at>                              |
 // +-----------------------------------------------------------------------+
 //
-// $Id: TreeMenu.js,v 1.4 2004/01/04 08:13:41 chriskl Exp $
+// $Id: TreeMenu.js,v 1.5 2004/02/02 06:32:18 chriskl Exp $
 
+/**
+* Function to create copies of objects which are
+* normally passed around by references (Arrays for example)
+*/
+function arrayCopy(input)
+{
+       var output = new Array(input.length);
+
+       for (i in input) {
+               if (typeof(input[i]) == 'array') {
+                       output[i] = arrayCopy(input[i]);
+               } else {
+                       output[i] = input[i];
+               }
+       }
+
+       return output;
+}
 
 /**
 * TreeMenu class
@@ -48,7 +66,8 @@
                this.usePersistence   = usePersistence;
                this.noTopLevelImages = noTopLevelImages;
                this.n                = new Array();
-       
+               this.output           = '';
+
                this.nodeRefs       = new Array();
                this.branches       = new Array();
                this.branchStatus   = new Array();
                var expanded      = arguments[3] ? arguments[3] : false;
                var visibility    = arguments[4] ? arguments[4] : 'inline';
                var parentLayerID = arguments[5] ? arguments[5] : null;
-       
+
                var currentlevel  = level.length;
-       
+
                for (var i=0; i<nodes.length; i++) {
                
                        level[currentlevel] = i+1;
                        layerID = this.myname + '_' + 'node_' + this.implode('_', level);
-       
+
                        /**
             * Store this object in the nodeRefs array
             */
                * Make sure visibility is correct based on parent status
                */
                        visibility =  this.checkParentVisibility(layerID) ? visibility : 'none';
-       
+
                        /**
                * Setup branch status and build an indexed array
                        * of branch layer ids
                        /**
                * Branch images
                */
-                       var gifname = nodes[i].n.length && this.doesMenu() && nodes[i].isDynamic ? (expanded ? 'minus' : 'plus') : 'branch';
-                       var iconimg = nodes[i].icon ? this.stringFormat('<img border="0" src="{0}/{1}" width="20" height="20" align="top" id="icon_{2}">', this.iconpath, nodes[i].icon, layerID) : '';
+                       var gifname  = nodes[i].n.length && this.doesMenu() && nodes[i].isDynamic ? (expanded ? 'minus' : 'plus') : 'branch';
+                       var iconName = expanded && nodes[i].expandedIcon ? nodes[i].expandedIcon : nodes[i].icon;
+                       var iconimg  = nodes[i].icon ? this.stringFormat('<img src="{0}/{1}" width="20" height="20" border="0" align="top" id="icon_{2}">', this.iconpath, iconName, layerID) : '';
                        
                        /**
                        * Add event handlers
                        * IMPORTANT:
                        * document.write()ing the string: '<div style="display:...' will screw up nn4.x
                */
-                       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}">', nodes[i].cssClass ? nodes[i].cssClass : this.defaultClass);
-                       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) : '';
-                       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);
-                       var linkTarget  = nodes[i].linkTarget ? nodes[i].linkTarget : this.linkTarget;
-                       var linkStart   = nodes[i].link ? this.stringFormat('<a href="{0}" target="{1}">', nodes[i].link, linkTarget) : '';
-                       var linkEnd     = nodes[i].link ? '</a>' : '';
-                       var browseStart = nodes[i].iconLink ? '<a target="detail" href="'+nodes[i].iconLink+'">' : '';
-                       var browseEnd   = nodes[i].iconLink ? '</a>' : '';
-
-                       output = this.stringFormat('{0}<nobr>{1}{2}{3}{4}{5}{6}<span {7}>{8}</span>{9}</nobr><br></div>',
+                       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}">', nodes[i].cssClass ? nodes[i].cssClass : this.defaultClass);
+                       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) : '';
+                       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);
+                       var linkTarget= nodes[i].linkTarget ? nodes[i].linkTarget : this.linkTarget;
+                       var linkStart = nodes[i].link ? this.stringFormat('<a href="{0}" target="{1}">', nodes[i].link, linkTarget) : '';
+
+                       var linkEnd   = nodes[i].link ? '</a>' : '';
+               var browseStart = nodes[i].iconLink ? '<a target="detail" href="'+nodes[i].iconLink+'">' : '';
+               var browseEnd   = nodes[i].iconLink ? '</a>' : '';
+
+                       this.output += this.stringFormat('{0}<nobr>{1}{2}{3}{4}{5}{6}<span {7}>{8}</span>{9}</nobr><br></div>',
                                          layerTag,
                                                          prepend,
                                          parentLayerID == null && (nodes.length == 1 || this.noTopLevelImages) ? '' : imgTag,
                                                          eventHandlers,
                                                          nodes[i].title,
                                                          linkEnd);
-       
-                       /**
-               * Write out the HTML. Uses document.write for speed over layers and
-                       * innerHTML. This however means no dynamic adding/removing nodes on
-                       * the client side. This could be conditional I guess if dynamic
-                       * adding/removing is required.
-               */
-                       document.write(output + "\r\n");
 
                        /**
                * Traverse sub nodes ?
                                } else {
                                        var newPrepend = prepend + this.stringFormat('<img src="{0}/linebottom.gif" width="20" height="20" align="top">', this.iconpath);
                                }
-       
+
                                this.drawMenu(nodes[i].n,
-                                             level,
+                                             arrayCopy(level),
                                              newPrepend,
                                              nodes[i].expanded,
                                              expanded ? 'inline' : 'none',
                }
        }
 
+/**
+* Writes the output generated by drawMenu() to the page
+*/
+       TreeMenu.prototype.writeOutput = function ()
+       {
+               document.write(this.output);
+       }
+
 /**
 * Toggles a branches visible status. Called from resetBranches()
 * and also when a +/- graphic is clicked.
                var currentDisplay = this.getLayer(layerID).style.display;
                var newDisplay     = (this.branchStatus[layerID] && currentDisplay == 'inline') ? 'none' : 'inline';
                var fireEvents     = arguments[2] != null ? arguments[2] : true;
-       
+
                for (var i=0; i<this.layerRelations[layerID].length; i++) {
-       
+
                        if (this.branchStatus[this.layerRelations[layerID][i]]) {
                                this.toggleBranch(this.layerRelations[layerID][i], false);
                        }
                        var imgSrc = document.images['icon_' + layerID].src;
        
                        if (this.nodeRefs[layerID].icon && this.nodeRefs[layerID].expandedIcon) {
-                               //alert(imgSrc.indexOf(this.nodeRefs[layerID].expandedIcon));
                                var newSrc = (imgSrc.indexOf(this.nodeRefs[layerID].expandedIcon) == -1 ? this.nodeRefs[layerID].expandedIcon : this.nodeRefs[layerID].icon);
        
                                document.images['icon_' + layerID].src = this.iconpath + '/' + newSrc;
 */
        TreeMenu.prototype.doesMenu = function ()
        {
-               return (is_ie4up || is_nav6up || is_gecko || is_opera7 || is_konqueror);
+               return (is_ie4up || is_nav6up || is_gecko || is_opera7);
        }
 
 /**
                if (!this.doesPersistence()) {
                        return false;
                }
-
+               
                this.loadCookie();
 
                for (var i=0; i<this.branches.length; i++) {
        
        var is_opera  = (agt.indexOf("opera") != -1);
        var is_opera7 = is_opera && (agt.indexOf("opera 7") != -1);
-       
-       var is_konqueror  = (agt.indexOf("konqueror") != -1);   
+
+       // Patch from Harald Fielker
+    if (agt.indexOf('konqueror') != -1) {
+        var is_nav    = false;
+        var is_nav6up = false;
+        var is_gecko  = false;
+        var is_ie     = true;
+        var is_ie4    = true;
+        var is_ie4up  = true;
+    }
 //--> end hide JavaScript
index 93cfa9e93def75e538dcc259193ae6b315a0d599..17314957c21f3698b1653bd6ff776768c52ffce1 100755 (executable)
@@ -33,7 +33,7 @@
 // |         Harald Radi <harald.radi@nme.at>                              |
 // +-----------------------------------------------------------------------+
 //
-// $Id: TreeMenu.php,v 1.3 2004/01/04 08:13:41 chriskl Exp $
+// $Id: TreeMenu.php,v 1.4 2004/02/02 06:32:18 chriskl Exp $
 
 /**
 * HTML_TreeMenu Class
@@ -100,7 +100,7 @@ class HTML_TreeMenu
     * are Wolfram Kriesings' PEAR Tree class, and Richard Heyes' (me!)
     * Tree class (available here: http://www.phpguru.org/). This
     * method is intended to be used statically, eg:
-    * $treeMenu = &HTML_TreeMenu::import($myTreeStructureObj);
+    * $treeMenu = &HTML_TreeMenu::createFromStructure($myTreeStructureObj);
     *
     * @param  array  $params   An array of parameters that determine
     *                          how the import happens. This can consist of:
@@ -171,7 +171,38 @@ class HTML_TreeMenu
                 break;
 
             /**
-            * Richard Heyes' (me!) Tree class
+            * Richard Heyes' (me!) second (array based) Tree class
+            */
+            case 'heyes_array':
+                // Need to create a HTML_TreeMenu object ?
+                if (!isset($params['treeMenu'])) {
+                    $treeMenu = &new HTML_TreeMenu();
+                    $parentID = 0;
+                } else {
+                    $treeMenu = &$params['treeMenu'];
+                    $parentID = $params['parentID'];
+                }
+                
+                // Loop thru the trees nodes
+                foreach ($params['structure']->getChildren($parentID) as $nodeID) {
+                    $data = $params['structure']->getData($nodeID);
+                    $parentNode = &$treeMenu->addItem(new HTML_TreeNode(array_merge($params['nodeOptions'], $data)));
+
+                    // Recurse ?
+                    if ($params['structure']->hasChildren($nodeID)) {
+                        $recurseParams['type']        = 'heyes_array';
+                        $recurseParams['parentID']    = $nodeID;
+                        $recurseParams['nodeOptions'] = $params['nodeOptions'];
+                        $recurseParams['structure']   = &$params['structure'];
+                        $recurseParams['treeMenu']    = &$parentNode;
+                        HTML_TreeMenu::createFromStructure($recurseParams);
+                    }
+                }
+                
+                break;
+
+            /**
+            * Richard Heyes' (me!) original OO based Tree class
             */
             case 'heyes':
             default:
@@ -201,55 +232,55 @@ class HTML_TreeMenu
 
         return $treeMenu;
     }
-       
-       /**
+    
+    /**
     * Creates a treeMenu from XML. The structure of your XML should be
-       * like so:
-       *
-       * <treemenu>
-       *     <node text="First node" icon="folder.gif" expandedIcon="folder-expanded.gif" />
-       *     <node text="Second node" icon="folder.gif" expandedIcon="folder-expanded.gif">
-       *         <node text="Sub node" icon="folder.gif" expandedIcon="folder-expanded.gif" />
-       *     </node>
-       *     <node text="Third node" icon="folder.gif" expandedIcon="folder-expanded.gif">
-       * </treemenu>
-       *
-       * Any of the options you can supply to the HTML_TreeNode constructor can be supplied as
-       * attributes to the <node> tag. If there are no subnodes for a particular node, you can
-       * use the XML shortcut <node ... /> instead of <node ... ></node>. The $xml argument can
-       * be either the XML as a string, or an pre-created XML_Tree object. Also, this method
-       * REQUIRES my own Tree class to work (http://phpguru.org/tree.html). If this has not
-       * been include()ed or require()ed this method will die().
-       *
-       * @param  mixed  $xml  This can be either a string containing the XML, or an XML_Tree object
-       *                      (the PEAR::XML_Tree package).
-       * @return object       The HTML_TreeMenu object
-    */
-       function createFromXML($xml)
-       {
-               if (!class_exists('Tree')) {
-                       die('Could not find Tree class');
-               }
-
-               // Supplied $xml is a string
-               if (is_string($xml)) {
-                       require_once('XML/Tree.php');
-                       $xmlTree = &new XML_Tree();
-                       $xmlTree->getTreeFromString($xml);
-
-               // Supplied $xml is an XML_Tree object
-               } else {
-                       $xmlTree = $xml;
-               }
-
-               // Now process the XML_Tree object, setting the XML attributes
-               // to be the tag data (with out the XML tag name or contents).
-               $treeStructure = Tree::createFromXMLTree($xmlTree, true);
-               $treeStructure->nodes->traverse(create_function('&$node', '$tagData = $node->getTag(); $node->setTag($tagData["attributes"]);'));
-
-               
-               return HTML_TreeMenu::createFromStructure(array('structure' => $treeStructure));
-       }
+    * like so:
+    *
+    * <treemenu>
+    *     <node text="First node" icon="folder.gif" expandedIcon="folder-expanded.gif" />
+    *     <node text="Second node" icon="folder.gif" expandedIcon="folder-expanded.gif">
+    *         <node text="Sub node" icon="folder.gif" expandedIcon="folder-expanded.gif" />
+    *     </node>
+    *     <node text="Third node" icon="folder.gif" expandedIcon="folder-expanded.gif">
+    * </treemenu>
+    *
+    * Any of the options you can supply to the HTML_TreeNode constructor can be supplied as
+    * attributes to the <node> tag. If there are no subnodes for a particular node, you can
+    * use the XML shortcut <node ... /> instead of <node ... ></node>. The $xml argument can
+    * be either the XML as a string, or an pre-created XML_Tree object. Also, this method
+    * REQUIRES my own Tree class to work (http://phpguru.org/tree.html). If this has not
+    * been include()ed or require()ed this method will die().
+    *
+    * @param  mixed  $xml  This can be either a string containing the XML, or an XML_Tree object
+    *                      (the PEAR::XML_Tree package).
+    * @return object       The HTML_TreeMenu object
+    */
+    function createFromXML($xml)
+    {
+        if (!class_exists('Tree')) {
+            die('Could not find Tree class');
+        }
+
+        // Supplied $xml is a string
+        if (is_string($xml)) {
+            require_once('XML/Tree.php');
+            $xmlTree = &new XML_Tree();
+            $xmlTree->getTreeFromString($xml);
+
+        // Supplied $xml is an XML_Tree object
+        } else {
+            $xmlTree = $xml;
+        }
+
+        // Now process the XML_Tree object, setting the XML attributes
+        // to be the tag data (with out the XML tag name or contents).
+        $treeStructure = Tree::createFromXMLTree($xmlTree, true);
+        $treeStructure->nodes->traverse(create_function('&$node', '$tagData = $node->getTag(); $node->setTag($tagData["attributes"]);'));
+
+        
+        return HTML_TreeMenu::createFromStructure(array('structure' => $treeStructure));
+    }
 } // HTML_TreeMenu
 
 
@@ -354,11 +385,13 @@ class HTML_TreeNode
     *                         o link          The link for the node, defaults to blank
     *                         o icon          The icon for the node, defaults to blank
     *                         o expandedIcon  The icon to show when the node is expanded
-    *                         o class         The CSS class for this node, defaults to blank
+    *                         o cssClass      The CSS class for this node, defaults to blank
     *                         o expanded      The default expanded status of this node, defaults to false
     *                                         This doesn't affect non dynamic presentation types
     *                         o linkTarget    Target for the links. Defaults to linkTarget of the
     *                                         HTML_TreeMenu_Presentation.
+    *                         o iconLink      Target for the icon link. Defaults to iconLink of the
+    *                                         HTML_TreeMenu_Presentation.
     *                         o isDynamic     If this node is dynamic or not. Only affects
     *                                         certain presentation types.
     *                         o ensureVisible If true this node will be made visible despite the expanded
@@ -380,7 +413,7 @@ class HTML_TreeNode
         $this->isDynamic     = true;
         $this->ensureVisible = false;
         $this->linkTarget    = null;
-       $this->iconLink    = '';
+        $this->iconLink      = null;
 
         $this->parent        = null;
         $this->events        = $events;
@@ -552,6 +585,9 @@ class HTML_TreeMenu_DHTML extends HTML_TreeMenu_Presentation
     *                         is achieved using cookies. Default is true.
     *  o noTopLevelImages  -  Whether to skip displaying the first level of images if
     *                         there is multiple top level branches.
+    *  o maxDepth          -  The maximum depth of indentation. Useful for ensuring
+    *                         deeply nested trees don't go way off to the right of your
+    *                         page etc. Defaults to no limit.
     *
     * And also a boolean for whether the entire tree is dynamic or not.
     * This overrides any perNode dynamic settings.
@@ -567,6 +603,7 @@ class HTML_TreeMenu_DHTML extends HTML_TreeMenu_Presentation
 
         // Defaults
         $this->images           = 'images';
+        $this->maxDepth         = 0;        // No limit
         $this->linkTarget       = '_self';
         $this->defaultClass     = '';
         $this->usePersistence   = true;
@@ -588,7 +625,7 @@ class HTML_TreeMenu_DHTML extends HTML_TreeMenu_Presentation
     function toHTML()
     {
         static $count = 0;
-        $menuObj = 'objTreeMenu_' . ++$count;
+        $menuObj     = 'objTreeMenu_' . ++$count;
 
         $html  = "\n";
         $html .= '<script language="javascript" type="text/javascript">' . "\n\t";
@@ -612,7 +649,9 @@ class HTML_TreeMenu_DHTML extends HTML_TreeMenu_Presentation
             }
         }
 
-         $html .= sprintf("\n\t%s.drawMenu();", $menuObj);
+        $html .= sprintf("\n\t%s.drawMenu();", $menuObj);
+        $html .= sprintf("\n\t%s.writeOutput();", $menuObj);
+
         if ($this->usePersistence && $this->isDynamic) {
             $html .= sprintf("\n\t%s.resetBranches();", $menuObj);
         }
@@ -626,29 +665,34 @@ class HTML_TreeMenu_DHTML extends HTML_TreeMenu_Presentation
     *
     * @access private
     */
-    function _nodeToHTML($nodeObj, $prefix, $return = 'newNode')
+    function _nodeToHTML($nodeObj, $prefix, $return = 'newNode', $currentDepth = 0, $maxDepthPrefix = null)
     {
+        $prefix = empty($maxDepthPrefix) ? $prefix : $maxDepthPrefix;
+        
         $expanded  = $this->isDynamic ? ($nodeObj->expanded  ? 'true' : 'false') : 'true';
         $isDynamic = $this->isDynamic ? ($nodeObj->isDynamic ? 'true' : 'false') : 'false';
         $html = sprintf("\t %s = %s.addItem(new TreeNode('%s', %s, %s, %s, %s, '%s', '%s', %s, '%s'));\n",
                         $return,
                         $prefix,
-                        $nodeObj->text,
-                        !empty($nodeObj->icon) ? "'" . $nodeObj->icon . "'" : 'null',
+                        addSlashes($nodeObj->text),
+                        !empty($nodeObj->icon) ? "'" . addSlashes($nodeObj->icon) . "'" : 'null',
                         !empty($nodeObj->link) ? "'" . $nodeObj->link . "'" : 'null',
                         $expanded,
                         $isDynamic,
-                        $nodeObj->cssClass,
-                        $nodeObj->linkTarget,
-                        !empty($nodeObj->expandedIcon) ? "'" . $nodeObj->expandedIcon . "'" : 'null',
-                       $nodeObj->iconLink
-                       );
+                        addSlashes($nodeObj->cssClass),
+                        addSlashes($nodeObj->linkTarget),
+                        !empty($nodeObj->expandedIcon) ? "'" . addSlashes($nodeObj->expandedIcon) . "'" : 'null',
+                        $nodeObj->iconLink);
 
         foreach ($nodeObj->events as $event => $handler) {
             $html .= sprintf("\t %s.setEvent('%s', '%s');\n",
                              $return,
                              $event,
-                             str_replace(array("\r", "\n", "'"), array('\r', '\n', "\'"), $handler));
+                             str_replace(array("\r", "\n", "'", "\\"), array('\r', '\n', "\'", "\\\\"), $handler));
+        }
+
+        if ($this->maxDepth > 0 AND $currentDepth == $this->maxDepth) {
+            $maxDepthPrefix = $prefix;
         }
 
         /**
@@ -656,7 +700,7 @@ class HTML_TreeMenu_DHTML extends HTML_TreeMenu_Presentation
         */
         if (!empty($nodeObj->items)) {
             for ($i=0; $i<count($nodeObj->items); $i++) {
-                $html .= $this->_nodeToHTML($nodeObj->items[$i], $return, $return . '_' . ($i + 1));
+                $html .= $this->_nodeToHTML($nodeObj->items[$i], $return, $return . '_' . ($i + 1), $currentDepth + 1, $maxDepthPrefix);
             }
         }