CSS Friendly Adapters, a new look


I have promised Mark Rae I would post this for quite some time. If you go to www.asp.net, you can download the CSS Friendly adapters. They are found at http://www.asp.net/CssAdapters/.
 
The problem I had with the adapters is illustrated here:
 
<div class="AspNet-Menu-Horizontal">
    <ul class="AspNet-Menu">
       <li class="AspNet-Menu-WithChildren">
       <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic’)" class="AspNet-Menu-Link">Music</a>
        <ul>
          <li class="AspNet-Menu-Leaf">
              <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Classical’)" class="AspNet-Menu-Link">
                   Classical</a>
          </li>
          <li class="AspNet-Menu-WithChildren">
             <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Rock’)" class="AspNet-Menu-Link">
               Rock</a>
             <ul>
              <li class="AspNet-Menu-Leaf">
               <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Rock\Electric’)" class="AspNet-Menu-Link">
                 Electric</a>
              </li>
              <li class="AspNet-Menu-Leaf">
               <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Rock\Acoustical’)" 
                      class="AspNet-Menu-Link">Acoustical</a>
              </li>
             </ul>
          </li>
          <li class="AspNet-Menu-Leaf">
           <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Jazz’)" class="AspNet-Menu-Link">Jazz</a>
          </li>
       </ul>
      </li>
      
<li class="AspNet-Menu-WithChildren">
       <span class="AspNet-Menu-NonLink">Movies</span>
    <ul>
      <li class="AspNet-Menu-Leaf">
       <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMovies\Action’)" class="AspNet-Menu-Link">Action</a>
      </li>
     <li class="AspNet-Menu-Leaf">
       <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMovies\Drama’)" class="AspNet-Menu-Link">Drama</a>
     </li>
     <li class="AspNet-Menu-Leaf">
        <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMovies\Musical’)" class="AspNet-Menu-Link">
                                Musical</a>
     </li>
    </ul>
   </li>
  </ul>
 </div>
Notice all of the classes at each level. They are unnecessary. I should be able to specify the menu class once and have it apply down the chain. Here is something more like the HTML I would like:
<div class="AspNet-Menu-Horizontal">
        <ul>
            <li>
                 <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic’)">
                <span>Music</span></a>
            <ul>
                <li>
                    <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Classical’)">
                    <span>Classical</span></a>
                </li>
                <li>
                    <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Rock’)">
                    <span>Rock</span></a>
                <ul>
                    <li>
                        <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Rock\Electric’)">
                        <span>Electric</span></a>
                    </li>
                    <li>
                        <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Rock\Acoustical’)">
                        <span>Acoustical</span></a>
                   </li>
                </ul>
              </li>
                <li>
                    <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMusic\Jazz’)">
                    <span>Jazz</span></a>
                </li>
            </ul>
        </li>
            <li>
               <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMMovies")">
               <span>Movies</span></a>
            </li>
        <ul>
            <li>
                <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMovies\Action’)">
                <span>Action</span></a>
           </li>
            <li>
                <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMovies\Drama’)">
                <span>Drama</span></a>
            </li>
            <li>
                <a href="javascript:__doPostBack(‘EntertainmentMenu’,’bMovies\Musical’)">
                <span>Musical</span></a>
            </li>
        </ul>
      </li>
    </ul>
</div>

In order to accomplish this, you have to edit the MenuAdapter.cs file to get rid of the code that is class specific. The bits that are different are shown in the following code snippet (highlighted):
 
using System;
using System.IO;
using System.Web;
using System.Web.Configuration;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
 
namespace CSSFriendly
{
 public class MenuAdapter : System.Web.UI.WebControls.Adapters.MenuAdapter
 {
  private WebControlAdapterExtender _extender = null;
  private WebControlAdapterExtender Extender
  {
   get
   {
    if (((_extender == null) && (Control != null)) ||
     ((_extender != null) && (Control != _extender.AdaptedControl)))
    {
     _extender = new WebControlAdapterExtender(Control);
    }
    System.Diagnostics.Debug.Assert(_extender != null, "CSS Friendly adapters internal error", "Null extender instance");
    return _extender;
   }
  }
  protected override void OnInit(EventArgs e)
  {
   base.OnInit(e);
   if (Extender.AdapterEnabled)
   {
    RegisterScripts();
   }
  }
  private void RegisterScripts()
  {
   Extender.RegisterScripts();
   string folderPath = WebConfigurationManager.AppSettings.Get("CSSFriendly-JavaScript-Path");
   if (String.IsNullOrEmpty(folderPath))
   {
    folderPath = "~/JavaScript";
   }
   //string filePath = folderPath.EndsWith("/") ? folderPath + "MenuAdapter.js" : folderPath + "/MenuAdapter.js";
   //Page.ClientScript.RegisterClientScriptInclude(GetType(), GetType().ToString(), Page.ResolveUrl(filePath));

  }
  protected override void RenderBeginTag(HtmlTextWriter writer)
  {
   if (Extender.AdapterEnabled)
   {
    Extender.RenderBeginTag(writer, "AspNet-Menu-" + Control.Orientation.ToString());
   }
   else
   {
    base.RenderBeginTag(writer);
   }
  }
  protected override void RenderEndTag(HtmlTextWriter writer)
  {
   if (Extender.AdapterEnabled)
   {
    Extender.RenderEndTag(writer);
   }
   else
   {
    base.RenderEndTag(writer);
   }
  }
  protected override void RenderContents(HtmlTextWriter writer) 
  {
   if (Extender.AdapterEnabled)
   {
    //writer.Indent++;
    BuildItems(Control.Items, 1, writer);
    //writer.Indent–;
    writer.WriteLine();

   }
   else
   {
    base.RenderContents(writer);
   }
  }
  private void BuildItems(MenuItemCollection items, int level, HtmlTextWriter writer)
  {
   if (items.Count > 0)
   {
    writer.WriteLine();
    writer.WriteBeginTag("ul");
    //if (isRoot)
    //{
    // writer.WriteAttribute("class", "AspNet-Menu");
    //}
    writer.Write(HtmlTextWriter.TagRightChar);
    writer.Indent++;
        
    foreach (MenuItem item in items)
    {
     BuildItem(item, writer, level + 1);
    }
    writer.Indent–;
    writer.WriteLine();
    writer.WriteEndTag("ul");
   }
  }
  private void BuildItem(MenuItem item, HtmlTextWriter writer, int level)
  {
   Menu menu = Control as Menu;
   if ((menu != null) && (item != null) && (writer != null))
   {
    writer.WriteLine();
    writer.WriteBeginTag("li");
    //string theClass = (item.ChildItems.Count > 0) ? "AspNet-Menu-WithChildren" : "AspNet-Menu-Leaf";
    //string selectedStatusClass = GetSelectStatusClass(item);
    //if (!String.IsNullOrEmpty(selectedStatusClass))
    //{
    // theClass += " " + selectedStatusClass;
    //}
    //writer.WriteAttribute("class", theClass);
    writer.Write(HtmlTextWriter.TagRightChar);
    //writer.Indent++;
    //writer.WriteLine();
    if (((item.Depth < menu.StaticDisplayLevels) && (menu.StaticItemTemplate != null)) ||
     ((item.Depth >= menu.StaticDisplayLevels) && (menu.DynamicItemTemplate != null)))
    {
     writer.WriteBeginTag("div");
     writer.WriteAttribute("class", GetItemClass(menu, item));
     writer.Write(HtmlTextWriter.TagRightChar);
     writer.Indent++;
     writer.WriteLine();
     MenuItemTemplateContainer container = new MenuItemTemplateContainer(menu.Items.IndexOf(item), item);
     if ((item.Depth < menu.StaticDisplayLevels) && (menu.StaticItemTemplate != null))
     {
      menu.StaticItemTemplate.InstantiateIn(container);
     }
     else
     {
      menu.DynamicItemTemplate.InstantiateIn(container);
     }
     container.DataBind();
     container.RenderControl(writer);
     writer.Indent–;
     writer.WriteLine();
     writer.WriteEndTag("div");
    }
    else
    {
     if (IsLink(item))
     {
      writer.WriteBeginTag("a");
      if (!String.IsNullOrEmpty(item.NavigateUrl))
      {
       writer.WriteAttribute("href", Page.Server.HtmlEncode(menu.ResolveClientUrl(item.NavigateUrl)));
      }
      else
      {
       writer.WriteAttribute("href", Page.ClientScript.GetPostBackClientHyperlink(menu, "b" + item.ValuePath.Replace(menu.PathSeparator.ToString(), "\"), true));
      }
      //writer.WriteAttribute("class", GetItemClass(menu, item));
      WebControlAdapterExtender.WriteTargetAttribute(writer, item.Target);
      if (!String.IsNullOrEmpty(item.ToolTip))
      {
       writer.WriteAttribute("title", item.ToolTip);
      }
      else if (!String.IsNullOrEmpty(menu.ToolTip))
      {
       writer.WriteAttribute("title", menu.ToolTip);
      }
      writer.Write(HtmlTextWriter.TagRightChar);
 
      writer.Indent++;
      writer.WriteLine();
     }
     else
     {
      writer.WriteBeginTag("span");
      writer.WriteAttribute("class", GetItemClass(menu, item));
      writer.Write(HtmlTextWriter.TagRightChar);
      //writer.Indent++;
      //writer.WriteLine();

     }
     if (!String.IsNullOrEmpty(item.ImageUrl))
     {
      writer.WriteBeginTag("img");
      writer.WriteAttribute("src", menu.ResolveClientUrl(item.ImageUrl));
      writer.WriteAttribute("alt", !String.IsNullOrEmpty(item.ToolTip) ? item.ToolTip : (!String.IsNullOrEmpty(menu.ToolTip) ? menu.ToolTip : item.Text));
      writer.Write(HtmlTextWriter.SelfClosingTagEnd);
     }
     //writer.Write(item.Text);
     
     writer.WriteBeginTag("span");
     writer.Write(HtmlTextWriter.TagRightChar);
     writer.Write(item.Text);
     writer.WriteEndTag("span");
     if (IsLink(item))
     {
      writer.Indent–;
      writer.WriteEndTag("a");
     }
     else
     {
      writer.Indent–;
      writer.WriteEndTag("span");
     }
    }
    if ((item.ChildItems != null) && (item.ChildItems.Count > 0))
    {
     BuildItems(item.ChildItems, level, writer);
    }
    //writer.Indent–;
    //writer.WriteLine();

    writer.WriteEndTag("li");
   }//if ((menu != null) && (item != null) && (writer != null))
  }
  private bool IsLink(MenuItem item)
  {
   return (item != null) && item.Enabled && ((!String.IsNullOrEmpty(item.NavigateUrl)) || item.Selectable);
  }
  private string GetItemClass(Menu menu, MenuItem item)
  {
   string value = "AspNet-Menu-NonLink";
   if (item != null)
   {
    if (((item.Depth < menu.StaticDisplayLevels) && (menu.StaticItemTemplate != null)) ||
     ((item.Depth >= menu.StaticDisplayLevels) && (menu.DynamicItemTemplate != null)))
    {
     value = "AspNet-Menu-Template";
    }
    else if (IsLink(item))
    {
     value = "AspNet-Menu-Link";
    }
    string selectedStatusClass = GetSelectStatusClass(item);
    if (!String.IsNullOrEmpty(selectedStatusClass))
    {
     value += " " + selectedStatusClass;
    }
   }
   return value;
  }
  private string GetSelectStatusClass(MenuItem item)
  {
   string value = "";
   if (item.Selected)
   {
    value += " AspNet-Menu-Selected";
   }
   else if (IsChildItemSelected(item))
   {
    value += " AspNet-Menu-ChildSelected";
   }
   else if (IsParentItemSelected(item))
   {
    value += " AspNet-Menu-ParentSelected";
   }
   return value;
  }
  private bool IsChildItemSelected(MenuItem item)
  {
   bool bRet = false;
   if ((item != null) && (item.ChildItems != null))
   {
    bRet = IsChildItemSelected(item.ChildItems);
   }
   return bRet;
  }
  private bool IsChildItemSelected(MenuItemCollection items)
  {
   bool bRet = false;
   if (items != null)
   {
    foreach (MenuItem item in items)
    {
     if (item.Selected || IsChildItemSelected(item.ChildItems))
     {
      bRet = true;
      break;
     }
    }
   }
   return bRet;
  }
  private bool IsParentItemSelected(MenuItem item)
  {
   bool bRet = false;
   if ((item != null) && (item.Parent != null))
   {
    if (item.Parent.Selected)
    {
     bRet = true;
    }
    else
    {
     bRet = IsParentItemSelected(item.Parent);
    }
   }
   return bRet;
  }
 }
}
 
I need to check the code and make sure that is all that has to be done to the code. The project backup I found is a bit jumbled, but this is the basics of getting rid of the need for all of the class definitions. Once I am sure this is everything needed, I will post the entire code in a project so you can use it easily.
 
Peace and Grace,
Greg
 
Twitter: @gbworld
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: