I am getting a little excited for what is in store for the community with the upcoming release of the DotNetNuke Webcontrols v2.0. Unfortunately, I have not had much time to blog on what I have been working on. This blog entry is meant as a means to allow the community to offer constructive feedback on the direction of one of the core controls found in DotNetNuke, the DNNMenu.
Before I discuss where we are going, lets review where we started and how we got to this point. The first Menu control within DNN was the SolpartMenu. It provided a hierarchical navigation structure to your portal. It was developed to work against many of the older browsers like Netscape, MacIE, IE5, etc. Back then I had the mentality that the control should handle all the different quirks between browsers. This caused a lot of the rendering of the menu to be hardcoded to handle specific use cases across all browsers. Probably the easiest to explain is the embedded border logic found within solpart when you hover a menu. This has caused many skin developers headaches (including myself). Seeing that there was a lot of logic within Solpart that needed refactoring, and no easy way to make those changes without killing the hundreds of existing skins out there, I felt it was best to create a new menu. Additionally, the DNN project has been making strides to segregate itself from third party components. Therefore, I decided to offer the next version of the menu to the core. This version would utilize the ClientAPI, thus allowing the menu script to not contain any cross-browser logic when it needed to position itself. It could focus on the single idea of rendering the menu.
The original skin object dealing with the menu structure was hardcoded to both obtain the DNN tab hierarchy and populate the solpartmenu. In order to allow any control an easy means of integrating with the DNN core, I developed the Navigation Provider. With that in place, both the menu contents (styles, text, etc.) along with the control doing the rendering could easily be tweaked without the need to modify core code.
The navigation document above discusses some design decisions that were made. Namely, how should the hierarchy be passed down to the client. The tradeoff that was chosen was to do what was most efficient, and allowed for the most flexibility. This decision led to most controls rendering only a container control with expando properties attached.
<span class="NavRootNode" id="nav_NavMenu" orient="0" sysimgpath="Images/" imagepaths="images/" rarrowimg="Images/icon_arrow_right-sm.gif" carrowimg="Images/icon_arrow_right-sm.gif" css="NavRootNode" csschild="NavChildNodeDefault" csshover="NavHoverClass" csssel="NavSelClass" mbcss="NavMenuBarClass" mcss="NavMenuClass" cssicon="NavIconDefault"></span>
The structure for the menu would be passed separately as XML. When the control initialized, the xml would be read in and the menu's html would be created.
Decision to use Expandos
I still like the idea of having the main container object for the control contain all its properties directly on the element. However, custom expandos cause issues with conformance validation. In order to address this problem, version 2 of the webcontrols will now pass these parameters separately in a JSON. I borrowed this idea from how the AJAX Control toolkit functions. In fact, I even added similar attributes to the toolkit to automatically build this json string.
<ClientProperty(), ClientPropertyName("sysimgpath"), DefaultValue("")> _
Property SystemImagesPath() As String
This simple change allows the menu to render 100% valid XHTML code. (This of course, is not hard to do, as the only thing rendered to the client is a SPAN tag with an ID).
Decision to use XML
New RenderingMode Property
The menu now has a RenderMode property that supports a few different ways of rendering. When set to its default (Normal) the following will be rendered from the server to the client.
<span class="NavRootNode" id="ctl00_NavMenu"></span>
Many people have become concerned with this as they feel that this does not address search engine crawlers. What most fail to realize, is that the server-side control detects if a crawler is viewing the page (System.Web.HttpContext.Current.Request.Browser.Crawler), and if it returns true, a spider friendly version of the menu is rendered. Something like
div width="100%" class="DNNMenu NavMenuBarClass" name="nav$NavMenu" id="nav_NavMenu">
<div name="0" id="0" style="padding-left:0px;">
<span class=" "></span><a class="NavRootNode" href="default.aspx">
While this markup is far from pretty, it serves its purpose. Crawlers can obtain the values and I also hear they aren't that picky as to what the rendering looks like ;)
Still, there are those in the community who really want the capability of rendering an unordered list in a similar manner to the original SuckerFish implementation. Apparently, there is some mistrust as to whether the method provided by ASP.NET actually works. The reason I have never gone this approach is outlined in the document above. It states that the html markup for a control typically is larger than the raw data itself.
In order to appease this group of users, I have decided to add a new RenderingMode of UnorderedList to the menu. Instead of the server spitting a simple version of the span element, an
unordered list will be emitted to the client.
<ul class="NavRootNode" id="ctl00_NavMenu">
This is the part where I am hoping the users who love css rendering, especially the suckerfish fans can help. I can't seem to find any css menus that allow for an icon to show up to the left of the text. I would expect to be able to do something like the following and have it work fine across all browsers.
li><img src="folder.gif" /><a>
However, I cannot seem to find any other unordered list menus putting icons in their menus. Is this a limitation of this approach? Ideally, the menu would support an optional icon, where one item in a menu has an icon and the other does not, and things still line up (this is easily accomplished with tables). Also, I am struggling with finding an example of these menus that do not require fixed width submenus. I would like the menu to automatically expand to the size of the max width of the text contained. Any info on if this is possible to accomplish would be greatly appreciated.
The first version of the DNNMenu allowed for its client-side rendering to not use tables. Instead it placed the burden of getting the css right on the designer, something that few were able to do partially due to the reasons above. I fear that if I don't find the answers to these questions this new rendering mode will suffer the same fate.