Howdy All,
Johny come lately to this thread here, but I've just started working with AC, AC7 specifically.
I wanted to thank everyone for their contributions here, and as pay back, I wanted to share my successes with this confounded widget.
First of all, I saw some folks on this thread apparently getting stumped with the CSS overflow and HTML nobr tags that ComponentArt throws in by default. When I first installed this from the code Pat_king shared here, I was alarmed by both of these.
Turns out the CSS overflow, or "autoscroll" as ComponentArt calls it, is simple. Just add AutoScroll="false" to the properties:
Code: Select all
{... other properties ...}
EnableViewState="false"
AutoScroll="false"
runat="server">
Dealing with the nowraps -- technically nobr tags that ComponentArt wraps every item in the tree in -- was much more challenging.
On the surface, this was "theoretically" simple to handle too, with CSS; just find the nobr tags as children of the various classes set as properties in CA, and set the value for the white-space property to "normal" like so:
Code: Select all
.CatTreeNode nobr, .CatSelectedTreeNode nobr, .CatHoverTreeNode nobr {
white-space: normal;
}
Joy! That killed the "nowrap" effect . . . . but, dang it all!, we've got a new problem: it line wraps after every word ( pulling hair from head and wiskers from beard ).
To solve that, we need to apply width so there is room for the words to expand into before they wrap.
However, this is where it started getting really hairy ( or rather the opposite, as I lost so much hair and so many whiskers over it ).
CA produces the list in a way I really didn't expect. I'd have hoped for an unordered list, which would have made life simple here. But no, for reasons that I'm sure are probably sound from their perspective, each item in the list is actually wrapped in a table -- yeah, a TABLE! Can you believe that? What's worse, each subcat in the list is wrapped in a table with TWO colums, but top level cats are wrapped in a table with only ONE column ( though there is just a little bit of odd spacing to the left I'll address further down here ). That is, allocating that space for the text to fill into before wrapping was pretty tricky.
Finally, I came up with this: having applied the width of the overall category tree menu in .CatTreeView, we just need to be able to find these table cells correctly and give them a width of 100%. So, after much futsing around I finally came up with this:
Code: Select all
#leftSidebarPanel .section .content .CatTreeView > table td:first-child {
width: 100%;
}
#leftSidebarPanel .section .content .CatTreeView table td + td {
width: 100%;
}
NOTE: I had to be very specific here because I was using one of the canned "Glass" themes here, and CA was picking up styles from "#leftSidebarPanel .section .content table"
That is, first find tables contextually with just the one TD ( we can't just set all of the TD's to any width, as the subcats with two TD's will inherit that ), and then find the instances of a TD preceeded by a TD ( i.e., our subcat text; the first TD is populated by CA with a div with width set to the value of what was set for NodeIndent ). Now top level cats will fill out their space allotted and subcats won't get pushed to the right; they will just indent as specified in the NodeIndent property of CA in the first cell, and then expand to fill out the space allotted to them in the second cell. All is well. . . . EXCEPT ( of course! ) in IE 6. I tested in FireFox 2 & 3, IE 7, and Safari 3 for PC's, and it was all good in those browsers. I'd really love it if anyone would pick up the torch from here and figure out how this could be tweeked for IE 6.
However, I was still not finished pulling out hairs and whiskers . . . . There was still one other very bothersome issue with this confounded table layout: I was using background images on the menu.
The problem here is that whatever I had set for background on .CatTreeNode & .CatSelectedTreeNode, & .CatHoverTreeNode didn't apply to the left of these -- for the top level cats, there was a wee bit of space, and for the subcats, there was a space as large as the indent was set for. I needed to be able to background the images at a larger scope than these CSS classes would allow me to do here.
I hit the books on ComponentArt documentation and found that you can add a row property to each of these. So I revised Pat_king's code as follows ( adding a row property to each of these instances ):
Code: Select all
TreeView1.NodeCssClass = "CatTreeNode";
TreeView1.NodeRowCssClass = "CatTreeNodeRow";
TreeView1.SelectedNodeCssClass = "CatSelectedTreeNode";
TreeView1.SelectedNodeRowCssClass = "CatSelectedTreeNodeRow";
TreeView1.HoverNodeCssClass = "CatHoverTreeNode";
TreeView1.HoverNodeRowCssClass = "CatHoverTreeNodeRow";
...
NodeCssClass="CatTreeNode"
NodeRowCssClass="CatTreeNodeRow"
SelectedNodeCssClass="CatSelectedTreeNode"
SelectedNodeRowCssClass="CatSelectedTreeNodeRow"
HoverNodeCssClass="CatHoverTreeNode"
HoverNodeRowCssClass="CatHoverTreeNodeRow"
Then, for the CSS:
Code: Select all
#leftSidebarPanel .section .content .CatTreeView .CatTreeNodeRow {
background: #F6F5DD url('images/left_panel_item_bg.gif') no-repeat left top;
cursor: pointer;
}
#leftSidebarPanel .section .content .CatTreeView .CatHoverTreeNodeRow {
background:#DEF4E8 url('images/left_panel_item_bg_hover_sm.gif') repeat-x left top;
cursor: pointer;
}
#leftSidebarPanel .section .content .CatTreeView .CatSelectedTreeNodeRow {
background:#DEF4E8 url('images/left_panel_item_bg_hover_sm.gif') repeat-x left top;
cursor: pointer;
}
NOTE: Not sure why I had to be so specific in locating these this way while I could style .CatTreeView .CatTreeNode just fine without providing context like this, but for the "*Row" elements, I had to get this specific for them to work. This might be because of the styling in the "Glass" theme I was using which I noticed CA was inheriting in some contexts.
This provides the proper styling to the entire row ( minus what's in the div that CA stuffs the text into ). Unfortunately, it also means that the background image has to be loaded multiple times: for top level cats, there's the row background and the background behind the div for the text that CA produces, and for subcats there's that plus the table-row to the left.
After all of this, I honestly have to say that while it is super cool for AC to include CompentArt under their royalty free licensing for those who might find interesting advantages, I think this is entirely way too much overhead ( it's like going around the world just to cross the street ) and way more learning curve than one should expect from a typical user ( I'm an experienced programmer, and it took me two days of study & trial and error ). I really can't see why AC can't put out an "ExtendedCategoryList" control rather like the SimpleCategoryList control, but expanding to the subcategory list under the parent category selected writing it out as a standard nested unordered list, esp. as using ComponentArt for this dramatically slows down page load, not to mention what a big PITA it makes styling it in interesting ways.
At the end of all of this, I still can't get this looking right in IE6, so I'd really love it if someone would run with what I've pushed forward here and suggest a remedy for IE6 as well.
Finally, here is my complete source code given all of this. There are some contextual labels based on one of the "Glass" themes I started with -- so for some, this might just "plug & play" if you are using one of these themes as a base, and for others, you'll have to edit the CSS accordingly:
CategoryTreeView.ascx
Code: Select all
<%@ Control Language="C#" ClassName="CategoryTreeView" EnableViewState="false" %>
<%@ Register TagPrefix="ComponentArt" Namespace="ComponentArt.Web.UI" Assembly="ComponentArt.Web.UI" %>
<%--
<conlib>
<summary>Displays the categories in your store in a treeview.</summary>
<param name="CacheDuration" default="60">Number of minutes the category tree will remain cached in memory. Set to 0 to disable caching.</param>
</conlib>
--%>
<script runat="server">
//to clear category tree cache use this page ClearCategoryTreeCache.aspx
int _CacheDuration = 60;
public int CacheDuration
{
get { return _CacheDuration; }
set { _CacheDuration = value; }
}
protected void Page_Init(object sender, EventArgs e)
{
InitializeCategoryTree();
}
private void InitializeCategoryTree()
{
TreeView1.ShowLines = false;
TreeView1.ImagesBaseUrl = "/App_Themes/" + Page.Theme + "/images/CategoryTreeView/";
TreeView1.CssClass = "CatTreeView";
TreeView1.NodeCssClass = "CatTreeNode";
TreeView1.NodeRowCssClass = "CatTreeNodeRow";
TreeView1.SelectedNodeCssClass = "CatSelectedTreeNode";
TreeView1.SelectedNodeRowCssClass = "CatSelectedTreeNodeRow";
TreeView1.HoverNodeCssClass = "CatHoverTreeNode";
TreeView1.HoverNodeRowCssClass = "CatHoverTreeNodeRow";
GetCategoryTreeNodes();
// Specify the current category
int categoryId = PageHelper.GetCategoryId();
TreeViewNode node = TreeView1.FindNodeById(categoryId.ToString());
if (node != null)
{
node.TemplateId = "SelectedCategoryTemplate";
node.Expanded = true;
EnsureTreeNodeVisible(node);
}
}
private void GetCategoryTreeNodes()
{
string cacheKey = "53741CA849784C8DA262F53638A2A38F";
string categoryNodes = null;
if (_CacheDuration > 0)
{
// Check to see if category treeview is in the cache
categoryNodes = Cache.Get(cacheKey) as string;
}
if (categoryNodes == null)
{
GetCategoryNodesRecursive(0, TreeView1.Nodes);
Cache.Insert(cacheKey, TreeView1.GetXml(), null, DateTime.Now.AddMinutes(_CacheDuration), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, null);
}
else
{
// Load Nodes from the cached xml string
TreeView1.LoadXml(categoryNodes);
}
}
private void GetCategoryNodesRecursive(int categoryId, TreeViewNodeCollection nodes)
{
TreeViewNode node;
CategoryCollection subcategories = CategoryDataSource.LoadForParent(categoryId, true);
foreach (Category subcat in subcategories)
{
node = new TreeViewNode();
node.ID = subcat.CategoryId.ToString();
node.Text = subcat.Name;
node.NavigateUrl = subcat.NavigateUrl;
//node.ImageUrl = subcat.ThumbnailUrl;
nodes.Add(node);
GetCategoryNodesRecursive(subcat.CategoryId, node.Nodes);
}
}
private void EnsureTreeNodeVisible(TreeViewNode node)
{
TreeViewNode currentNode = node.ParentNode;
while (currentNode != null)
{
currentNode.Expanded = true;
currentNode = currentNode.ParentNode;
}
}
</script>
<asp:Panel ID="MainPanel" runat="server" CssClass="section">
<asp:Panel ID="HeaderPanel" runat="server" CssClass="header">
<h2 class="header"><asp:Localize ID="HeaderTextLabel" runat="server" Text="Categories"></asp:Localize></h2>
</asp:Panel>
<asp:Panel ID="TreePanel" runat="server" CssClass="content">
<ComponentArt:TreeView id="TreeView1"
Width="178px"
DragAndDropEnabled="false"
NodeEditingEnabled="false"
KeyboardEnabled="true"
CssClass="CatTreeView"
NodeCssClass="CatTreeNode"
NodeRowCssClass="CatTreeNodeRow"
SelectedNodeCssClass="CatSelectedTreeNode"
SelectedNodeRowCssClass="CatSelectedTreeNodeRow"
HoverNodeCssClass="CatHoverTreeNode"
HoverNodeRowCssClass="CatHoverTreeNodeRow"
DefaultImageWidth="0"
DefaultImageHeight="0"
ExpandCollapseImageWidth="0"
ExpandSelectedPath="true"
ExpandCollapseImageHeight="0"
NodeIndent="10"
ItemSpacing="0"
NodeLabelPadding="0"
CollapseImageUrl=""
ExpandImageUrl=""
ParentNodeImageUrl=""
LeafNodeImageUrl=""
ShowLines="false"
EnableViewState="false"
AutoScroll="false"
runat="server">
<Templates>
<ComponentArt:NavigationCustomTemplate id="SelectedCategoryTemplate">
<Template>
<strong><%# DataBinder.Eval(Container.DataItem, "Text") %></strong></Template>
</ComponentArt:NavigationCustomTemplate>
</Templates>
</ComponentArt:TreeView>
</asp:Panel>
</asp:Panel>
CSS:
Code: Select all
/******************************************************************************************/
/* styles for the category treeview (such as might show on the home page) */
/******************************************************************************************/
.CatTreeView {
width: 174px;
background: transparent;
}
#leftSidebarPanel .section .content .CatTreeView table {
width: 100%;
border-top: 0;
border-right: solid 1px #8ED4AF;
border-bottom: solid 1px #8ED4AF;
border-left: solid 1px #8ED4AF;
border-collapse:inherit!important;
background: transparent;
font-family: Arial, Verdana, Helvetica, sans-serif;
font-size: 12px;
}
#leftSidebarPanel .section .content .CatTreeView > table td:first-child {
width: 100%;
}
#leftSidebarPanel .section .content .CatTreeView table td + td {
width: 100%;
}
.CatTreeNode {
padding: 8px 3px 8px 13px;
background: #F6F5DD url('images/left_panel_item_bg.gif') no-repeat left top;
color: #661A29;
cursor: pointer;
}
#leftSidebarPanel .section .content .CatTreeView .CatTreeNodeRow {
background: #F6F5DD url('images/left_panel_item_bg.gif') no-repeat left top;
cursor: pointer;
}
.CatHoverTreeNode {
padding: 8px 3px 8px 26px;
background:#DEF4E8 url('images/left_panel_item_bg_hover.gif') no-repeat left top;
color: #006729;
cursor: pointer;
}
#leftSidebarPanel .section .content .CatTreeView .CatHoverTreeNodeRow {
background:#DEF4E8 url('images/left_panel_item_bg_hover_sm.gif') repeat-x left top;
cursor: pointer;
}
.CatSelectedTreeNode {
padding: 8px 3px 8px 26px;
color: #006729;
background:#DEF4E8 url('images/left_panel_item_bg_hover.gif') no-repeat left top;
cursor: pointer;
}
#leftSidebarPanel .section .content .CatTreeView .CatSelectedTreeNodeRow {
background:#DEF4E8 url('images/left_panel_item_bg_hover_sm.gif') repeat-x left top;
cursor: pointer;
}
.CatTreeNode nobr, .CatSelectedTreeNode nobr, .CatHoverTreeNode nobr {
white-space: normal;
}
/******************************************************************************************/
/* end styles for the category treeview (such as might show on the home page) */
/******************************************************************************************/
PS: If anyone wants to see this all in action, I've done this on BarParts.com ( though things might change aver this post )