|
|
Nov
14
Posted by:
Jon Henning
11/14/2007
For a long time now many skinners for DotNetNuke have felt like customizing individual menu items was like looking for the Holy Grail. All the menus I have contributed to the community (Solpart and DNNMenu) have always had the ability to customize each menu item. The problem always was
how do we allow DotNetNuke the ability to customize the items? The only place the unique menu structure is known is after the portal is created, well out of reach of someone providing a generic skin to fit any site. Sure there are those portal admins out there that know enough about css to make it work, but there still was a problem in how to access each item directly in css.
I have been considering options for how to overcome this for some time now, and am currently working on the 2.0 version of the webcontrols which should contain one possible solution. However, those controls are far from complete so I decided to offer a minor hack along the same lines.
First, let us consider eclayf's idea from the forums, where I borrowed the name of this blog entry from. The idea is to loop through all menu items and assign a background image to each item based off of the icon assigned. This allows the background image to be customized by the portal admin.
To try this idea out add the following code to your ascx page using the DNNMenu (not solpart). I tested with default blue for DNN.
<script type="text/javascript">
function setupMenuImageCss(id)
{
var menu = dnn.controls.controls[id + '_ctldnnNAV'];
assignImageCss(menu, menu.rootNode);
}
function assignImageCss(menu, parent)
{
var menuNode = new dnn.controls.DNNMenuNode(parent);
var iconCtl = menu.getChildControl(menuNode.id, 'icn');
if (iconCtl)
{
iconCtl.style.display = 'none'; //hide icon
var menuCtr = menu.getChildControl(menuNode.id, 'ctr');
menuCtr.style.backgroundImage = "url('" + iconCtl.src + "')";
}
for (var i=0; i < parent.childNodeCount(); i++)
{
assignImageCss(menu, parent.childNodes(i));
}
}
try
{
document.execCommand("BackgroundImageCache", false, true);
}
catch(err) {}
</script>
<script runat="server">
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
DotNetNuke.UI.Utilities.DNNClientAPI.AddBodyOnloadEventHandler(Me.Page, "setupMenuImageCss('" & dnnNAV.ClientID & "')")
End Sub
</script>
This should cause the icon images to be displayed as the background.
Note: I noticed that if your skin declares the background-color (as the default blue does), the hover will no longer display the background. If you change it to not set the background then the image remains.
While this works, it is far from ideal. For one thing the admin menu item icons are not customizeable. Probably the biggest shortcoming is you can only customize the image, which happens to meet eclayf's requirements, but not generic enough to implement for DotNetNuke.
The idea I have been toying with is allowing the next version of the menu to support known client-side IDs. My current thought is to allow the skin to decide whether to go this route by providing a "safe" known namespace. For example, in your skin you would have a property like ClientIDPrefix="jcompany", then on the client each node will be assigned a unique id, prefixed with that text. So the root would be jcompany__0, jcompany__1, etc. The child of
jcompany__2 would be jcompany__2_1, jcompany__2_2, etc. This way it would allow the skinner
to predefine as many levels as he/she sees fit, and as long as the user of the portal doesn't exceed the predefined number, the skin should work as originally intended. Even if the skinner doesn't provide the level necesssary (something like jcompany__2_2_1_3_5), there is nothing stopping the user from adding the css himself, perhaps copying the value from a class defined higher up. The only pitfal in this approach is the worry about overlapping prefixes with other controls on the page.
In order to try this concept out add the following code to you ascx file that uses the DNNMenu
<script type="text/javascript">
function setupMenuIds(id, prefix)
{
var menu = dnn.controls.controls[id + '_ctldnnNAV'];
assignMenuIds(menu, menu.rootNode, prefix, '');
}
function assignMenuIds(menu, parent, prefix, id)
{
var menuNode = new dnn.controls.DNNMenuNode(parent);
var menuCtr = menu.getChildControl(menuNode.id, 'ctr');
var newId = prefix + '_' + id;
if (menuCtr)
menuCtr.id = newId;
for (var i=0; i
<script runat="server">
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
DotNetNuke.UI.Utilities.DNNClientAPI.AddBodyOnloadEventHandler(Me.Page, "setupMenuIds('" & dnnNAV.ClientID & "', 'jcompany')")
End Sub
</script>
Then in your css file add something like
#jcompany__0
{
background: red;
}
#jcompany__1
{
background: blue;
}
#jcompany__1_0 td
{
background: green;
}
#jcompany__1_1 td
{
background: orange;
}
Note: It is worth noting that in general it is a bad idea to change the ids of a any control, as it most likely will break the control when it does a lookup by its id. In the DNNMenu's case, those references to the lookup are cached internally, thus this reassignment of ids will work.
Right now this is just an idea I'm toying with. If people like the approach I probably will include it in version 2.0 of the DNNMenu. Any feedback on this would be welcome.
Tags:
15 comment(s) so far...
Re: Searching for the "Holy Grail" of Menu Item Customization
The approach seems generic and wide enough - but, the incorporation of images and image pieces composited together as a menu item button needs to be more thorough or open. But, at least with what you are proposing it would pinpoint how and where to go in to make adjustments so instead of having a single background image I can do what I need - which 3 pieces, so the center would grow with the width of the menu item text.
Let me test this code out, and then maybe I will make adjustments to show you what I am needing and trying to do and what I suspect other portal builders need the flexibility to be able to do -- which is have more attributes or ability to really deeply reskin a menu in various ways.
Thank you for diving into this much needed additional way to customize DNN... it will help get DNN to a point where you won't be able to distinguish a DNN portal just by looking at the menu style at the top :-)
thx
David
By davidko on
7/10/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
Hi Jon,
What about using a full css menu ? (like HouseMenu)
SolpartMenu is not SEO friendly
By nrobles on
7/11/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
I am confused by what you mean to SEO friendly. If you mean search engine friendly, then I beg to differ. The menu will determine on the server-side whether or not a crawler is searching it, and if so spits out a SEO friendly version of the menu. For example, if you search Google for DotNetNuke, then click on one of the cached links you will see how Google sees the menu. For example http://209.85.165.104/search?q=cache:aDgxcsYq8ScJ:www.dotnetnuke.com/tabid/795/Default.aspx+dotnetnuke&hl=en&ct=clnk&cd=2&gl=us
That said, I have spent quite a bit of time allowing any menu to be plugged into DNN when I added the navigation providers. People are free to choose their own menu as they see fit. I happen to think the way I have implemented the menu provides the greatest flexibility and will produce the smallest footprint as its only sending down the raw data to the client. Most of my reasons for the design decisions are documented in this document http://www.dotnetnuke.com/LinkClick.aspx?fileticket=vCjeodeg5pk%3d&tabid=478&mid=857.
By jhenning@solpart.com on
7/11/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
"The menu will determine on the server-side whether or not a crawler is searching it, and if so spits out a SEO friendly version of the menu"
Very very bad. This is CLOAKING. You can get blacklisted for that. From a Search Engine Optimization point of view, the server has to deliver the same version, mostly because you can never be sure if the request comes from a Search Engine or not. Parsing the UserAgent parameter is not enough, and if you're talking about an updated database of IP adresses of the crawlers, forget it.
We are buliding on the long run great portals, with rich functionalities. But DNN is killing it by default (so to most of its users) with a XML-based navigation menu, complex and non-optimized urls. Moreover, on your document, you talk about Performance, server load and bandwidth : sorry but as far as I know, DNN generates a messy source code. and XML-based navigation wont optimized the whole thing that much.
The DotNetNuke.com homepage HTML code weights 147 KB ! Houston, we got a problem here... DNN portals are generally known as slow...
Hopefully, DNN has a fantastic provider-based architecture, so a lot of things can be tweaked. I don't see that much DNN portals on my google results.
I think SEO should be a priority. Avoid duplicate content, optimize keywords, descriptions, inner links. XHTML power ?
By the way, the supposed SEO-friendly version generated of the navigation is strange :inserted in a table ? The code is kinda ugly no ? with lots of
Use Unordered lists! The suckerfish model rules.
By nrobles on
7/12/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
wikipedia - http://en.wikipedia.org/wiki/Cloaking When a user is identified as a search engine spider, a server-side script delivers a different version of the web page, one that contains *** content *** not present on the visible page. Are you saying the content the menu presents is different or just how its rendered?
Regarding performance. The document discusses the approach the navigation controls (menu) takes. Why are you talking about everything else within DNN? Seems like you are side-stepping the issue of payload size by bringing up other issues.
Sounds like you are prioritizing unordered lists above all other tradeoffs.
Suggestion1: Make a menu that plugs into DNN and offer it to the community.
Suggestion2: Add your feedback on SEO prioritization to the Roadmap requests if you haven't already (http://www.dotnetnuke.com/Products/Development/Roadmap/tabid/616/Default.aspx).
By jhenning@solpart.com on
7/12/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
Why not just give it an ID based on the TabID? Wouldn't that be the most intuitive approach?
#MenuItem_36 { background: blue; }
By proeder on
7/18/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
proeder, Actually that is what is currently done (without the prefix). However, this does not allow a skinner (who has no idea of site layout, let alone IDs) offer a default look to each node that *may* be in the menu. I am trying to come up with a way that allows for customizations to individual menu items for both the skinner and the site admin.
By jhenning@solpart.com on
7/18/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
I keep getting this error in Internet Explorer:
'rootNode' is null or not an object
Does anyone know how to solve this? I'm just a newbie....
Thanks in advance
By stefandebie on
9/18/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
stefandebie, Please post questions like these in the forums
By jhenning@solpart.com on
9/18/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
I prefer an UL menu and have written my own, but to say the SolPart is not SEO friendly is utter nonsense. Dotnetnuke.com front page has a Google PR of 8 and pages inside the site do well too and that's with a SolPart menu. The cloaking argument is missing the point, the version that is rendered for down level browsers, like the google bot, has the same semantic content, it's just rendered differently.
By Isomies on
11/15/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
So basic concept is how to map the tabIDs to HTML entities such that designers can predefine the look and feel?
I don't get how what you outline will actually solve anything in terms of specific tabs. Unless DNN maps the connection, how would knowing id= jcompany__2_2 help you more than a general naming convention for all menus?
For instance:
By lancelong on
11/20/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
WOULD SOME ONE PLEASE TURN ON BASIC HTML FOR BLOGS!!!!
By lancelong on
11/20/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
lancelong, see this blog http://www.dotnetnuke.com/Community/Blogs/tabid/825/EntryID/1532/Default.aspx. I am providing both the skinner the ability to predefine styles by its position in the hierarchy, and I am allowing the end-user to define css per tabid.
By jhenning@solpart.com on
11/20/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
Ok, I understand. Have a look at my suggestion still (after tidyHTMLing up). I suggested it because positioning is a mix of classification and identification. All top level items can be styled in one line regardless of number of items. The IDs specify where in the menu they appear. The tab IDs allow specific pages to be targeted by savvy administrators or producers. I just though your concept was too granular. I'm on a bit of a rant but have you checked out YUI examples?http://developer.yahoo.com/yui/examples/menu/example07.html
By lancelong on
11/21/2007
|
Re: Searching for the "Holy Grail" of Menu Item Customization
Thanks for the post solved my problem for now.
Just a thought but if there was an ability to add a couple additional tokens into the LEft and right Html namely [Name], [TabId], [MenuLevel] it would allow for a great deal of flexibility in this area as well as adding in other custom functionality.
IE if there was a token for the TabName You could use NodeLeftHTMLRoot and NodeRightHTMLRoot to wrap the menu item in a Table with a tr and a td id="Menu_[Name]" and then set the background of the TD in the CSS.
By nmbt0 on
5/29/2008
|
|


Follow us on Twitter @DNNCorp or join the DotNetNuke Community on LinkedIn
|