Has anyone written any HTMLHelper classes for MVC that help with Yahoo's User Interface Library?
For instance I have written a helper method to convert a 'menu model' into the HTML markup needed to support the Yahoo Menu Control. The MVC pattern works well here because obviously if I chose to switch to a different menu implementation I can just write a new helper and not touch the model.
This code works for me but isn't fully tested and you're welcome to use it.
First we need a simple data structure for the menu model itself. You would add this to your page model with the normal MVC conventions. For instance I access a list of menu items from my view via ViewData.Model.MainMenu.MenuOptions
.
public class MenuItem
{
public string Text { get; set; }
public string Description { get; set; }
public string RouteURL { get; set; }
public bool SeparatorBefore { get; set; }
public List<MenuItem> MenuItems { get; set; }
}
Extension method. Put in a namespace that is accessible to your view.
public static class YUIExtensions
{
public static string RenderMenu(this HtmlHelper html, string id, List<MenuItem> menuItems)
{
// <div id="mnuTopNav" class="yuimenubar yuimenubarnav">
// <div class="bd">
// <ul class="first-of-type">
// <li class="yuimenubaritem first-of-type"><a class="yuimenubaritemlabel" href="#store">Store</a></li>
// <li class="yuimenubaritem"><a class="yuimenubaritemlabel" href="#products">Products</a>
// <div id="communication" class="yuimenu">
// <div class="bd">
// <ul>
// <li class="yuimenuitem"><a class="yuimenuitemlabel" href="http://360.yahoo.com">360&#176;</a></li>
// <li class="yuimenuitem"><a class="yuimenuitemlabel" href="http://mobile.yahoo.com">Mobile</a></li>
// <li class="yuimenuitem"><a class="yuimenuitemlabel" href="http://www.flickr.com">Flickr Photo Sharing</a></li>
// </ul>
// </div>
// </div>
// </li>
// </ul>
// </div>
//</div>
int menuId = 0;
HtmlGenericControl menuControl = CreateControl(html, id, 0, ref menuId, menuItems);
// render to string
StringWriter sw = new StringWriter();
HtmlTextWriter tw = new HtmlTextWriter(sw);
tw.Indent = 1;
menuControl.RenderControl(tw);
return sw.ToString();
}
private static HtmlGenericControl CreateControl(HtmlHelper html, string id, int level, ref int menuId, List<MenuItem> currentItems)
{
var menu = new HtmlGenericControl("div");
menu.Attributes["class"] = (level == 0) ? "yuimenubar yuimenubarnav" : "yuimenu";
menu.Attributes["id"] = id;
var div_bd = new HtmlGenericControl("div");
menu.Controls.Add(div_bd);
div_bd.Attributes["class"] = "bd";
HtmlGenericControl ul = null;
int i = 0;
foreach (var menuItem in currentItems)
{
if (ul == null || menuItem.SeparatorBefore)
{
ul = new HtmlGenericControl("ul");
div_bd.Controls.Add(ul);
if (i == 0)
{
ul.Attributes["class"] = "first-of-type";
}
}
var menuItem_li = new HtmlGenericControl("li");
menuItem_li.Attributes["class"] = (level == 0) ? "yuimenubaritem" : "yuimenuitem";
if (i == 0)
{
menuItem_li.Attributes["class"] += " first-of-type";
}
ul.Controls.Add(menuItem_li);
var href = new HtmlGenericControl("a");
href.Attributes["class"] = (level == 0) ? "yuimenubaritemlabel" : "yuimenuitemlabel";
href.Attributes["href"] = menuItem.RouteURL;
href.InnerHtml = menuItem.Text;
menuItem_li.Controls.Add(href);
if (menuItem.MenuItems != null && menuItem.MenuItems.Count > 0)
{
menuItem_li.Controls.Add(CreateControl(html, id + "_" + (menuId++), level + 1, ref menuId, menuItem.MenuItems));
}
i++;
}
return menu;
}
}
Stick this code where you want to generate the menu in your view (I have this in a master page):
<%= Html.RenderMenu("mnuTopNav", ViewData.Model.MainMenu.MenuOptions) %>
If you're lazy, or don't know about YUI you'll need this too in your <HEAD>
<!-- Combo-handled YUI CSS files: -->
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?2.6.0/build/menu/assets/skins/sam/menu.css">
<!-- Combo-handled YUI JS files: -->
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.6.0/build/yahoo-dom-event/yahoo-dom-event.js&2.6.0/build/container/container_core-min.js&2.6.0/build/menu/menu-min.js"></script>
This currently generates markup for top nav style navigation bar - but it could be easily modified.
I was hoping somebody else was doing the same for some of the other controls.
Seems like a good candidate for an open source project - but I dont have time to start that.
Implementation advice welcomed!