When using ASP.NET 2.0's built-in TreeView on a page with
<BASE target = "AnythingBut_Self"></BASE>
in the HEAD, the expand/collapse buttons fail to function. The reason
for this is that the hyperlinks generated for the expand/collapse
buttons includes javascript code that will execute in the frame
specified in the Base Target rather than the current document. To
remedy this, TreeView should render a target="_self" attribute for each
expand/collapse hyperlink.
The argument against this being a bug, of course, is that TreeView
includes a property called Target, which can be set to the desired
target (and Base Target cannot be set.) The reason I think it's better
to use Base Target is for large trees - not including a target for each
and every node saves just a little bit of extra bandwidth. (See the
JavaScript code below for my client-side work-around function called
FixTreeTargets.)
I also wasn't happy that the SelectNodeStyle isn't applied when a node
is clicked that has a NavigateUrl set, since I want the selection to be
visible while another frame shows the new page.
I created a JavaScript "wrapper" object for TreeView that allows a
selection style (I got lazy and didn't bother with SelectNodeStyle but
just a css class name instead) to be applied on click. Just call
initTheTree() from your body onload function. I haven't completely
tested this yet, but it seems to be working so far! (o;
// JScript File
var theTree;
function initTheTree() {
theTree = new ClientSideTree(document.getElementById("tvData"),
"TreeSelected", true);
}
function ClientSideTree(initTreeView, initSelectedClassName,
initCancelIfSelected) {
var objSelectedNode;
var objTreeView;
var strSelectedClassName;
var bolCancelIfSelected;
this.getTreeView = function () { return objTreeView; }
this.setTreeView = SetupTreeView;
this.getSelectedClassName = function () { return
strSelectedClassName; }
this.setSelectedClassName = function (val) { strSelectedClassName =
val; this.selectNode(objSelectedNode); }
this.getCancelIfSelected = function () { return bolCancelIfSelected;
}
this.setCancelIfSelected = function (val) { bolCancelIfSelected =
val; }
this.getSelectedNode = function () { return objSelectedNode; }
this.setSelectedNode = SelectNode;
this.selectNode = SelectNode; // Duplicate reference because it's
cool, OK!?
this.handleClick = HandleClick;
if (initTreeView)
this.setTreeView(initTreeView);
if (initSelectedClassName)
this.setSelectedClassName(initSelectedClassName);
if (initCancelIfSelected)
this.setCancelIfSelected(initCancelIfSelected);
function SetupTreeView(obj) {
objTreeView = obj;
objTreeView.onclick = this.handleClick;
FixTreeTargets();
}
function FixTreeTargets() { // Workaround for MS ASP.NET 2.0 TreeView
Bug
// Because Base Target may be set to some value other than _self,
// all Expand/Collapse link targets must be set to _self or they
will fail.
var allLinks = objTreeView.getElementsByTagName("A");
for (var i = 0; i < allLinks.length; i++) {
if (allLinks[i].href.indexOf("javascript:") > -1)
allLinks[i].target = "_self";
}
}
function HandleClick() {
//stop;
var obj = window.event.srcElement;
var objTarget;
switch (obj.tagName) {
case "A":
objTarget = obj
break;
case "IMG":
if (obj.src.indexOf("?") == -1) { // Expand/Collapse
img.src="xxx?xxx"
objTarget = obj.parentNode.parentNode.nextSibling.firstChild;
// Get Link
} else {
objTarget = null; // Ignore Expand/Collapse img
}
break;
}
window.status = "Clicked on: [" + obj.tagName + "]" + obj.id + "
src: " + obj.src;
if (objTarget) {
var prevSelectedNode = objSelectedNode;
SelectNode(objTarget);
if (objTarget == prevSelectedNode && bolCancelIfSelected)
return false; // If the selected object is reselected and
CancelIfSelected = true, cancel the click
}
}
function SelectNode(obj) {
if (objSelectedNode) {
RemoveSelectedClass(objSelectedNode);
}
if (obj) {
AddSelectedClass(obj);
objSelectedNode = obj;
}
}
function RemoveSelectedClass(obj) {
var c = obj.className;
var newClassName = "";
if (c) {
var cArray = c.split(" ");
for (var i = 0; i < cArray.length; i++) {
if (cArray[i] != strSelectedClassName) {
if (i > 0)
newClassName += " ";
newClassName += cArray[i];
}
}
obj.className = newClassName;
}
}
function AddSelectedClass(obj) {
if (obj.className && obj.className.length > 0)
obj.className += " " + strSelectedClassName;
else
obj.className = strSelectedClassName;
}
}
Don't hate the code too much - this is my first attempt at a JavaScript
object of any kind, although I've been messing with JavaScript in
general for a while.