// | 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
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
// | 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
* 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:
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:
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
* 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
$this->isDynamic = true;
$this->ensureVisible = false;
$this->linkTarget = null;
- $this->iconLink = '';
+ $this->iconLink = null;
$this->parent = null;
$this->events = $events;
* 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.
// Defaults
$this->images = 'images';
+ $this->maxDepth = 0; // No limit
$this->linkTarget = '_self';
$this->defaultClass = '';
$this->usePersistence = true;
function toHTML()
{
static $count = 0;
- $menuObj = 'objTreeMenu_' . ++$count;
+ $menuObj = 'objTreeMenu_' . ++$count;
$html = "\n";
$html .= '<script language="javascript" type="text/javascript">' . "\n\t";
}
}
- $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);
}
*
* @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;
}
/**
*/
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);
}
}