Just after writing that last post I decided to open the blinds to my window and immediately caught a glimpse of two young deer laying in our backyard, just chillaxin. So I quickly put my 100-400mm L on my XTi, snuck out the front and around the side of the house and caught a few shots.
Carlos Sastre has taken yellow all the way home today to win the Tour De France in the overall best rider (time) category. Congratulations to him and the whole CSC team who also took the overall best team classification as well as the white jersey (best young rider). Carlos beat out Cadel Evans by attacking on Alp d’Huez and holding everyone off in the final time trial.
The biking season is just coming into full swing for me. Unfortunately I got a late start because I wanted to work hard first this summer and make some money, then ease off and get into a nice rythm. Before this past week my average weekly mileage had been stuck around 20-30 miles. This week I have ridden 53 with the intention of riding more had my bike not been in the shop for half of it.
One of the goals of this season was much like the goal of the previous season: to get my 16 mile time to under 50 minutes. Today I set out to do this and finished with a time of 00:48:22.xxx! This means I averaged roughly 20 miles per hour over the entire course (if I did my math correctly) which is well above my previous best of 17mph average.
Now that I have knocked one item off my list it is time to continue and work on the others: weight loss and overall distance. Weight loss will come, I am sure of that, but my bike is definately hurting me on distance. It sucks my energy because of how much friction it has and is unreliable when ascending. My highest mileage to date is 40 miles, and the goal is to get to 75 miles by the end of the season.
Who knows, I may just do it.
The SharePoint Happenings Blog has a great post about customizing forms for your lists. I am using this to get rid of certain fields that I do not want to be entered when a new item is added. For instance, I default the Status field to “In Development” (Open/Assigned) and force the user to pick this by hiding the field.
What a post by David Millar. If you don’t follow professional cycling, then you may not know about the doping problem that has plagued the sport. Many say that one of the biggest reasons behind it is that the races are just too demanding. The Tour de France is incredibly long and has only a few rest days. The riders are expected to go over gigantic mountains, travel all over france and be able to do this day in and day out for days and days.
I say that is hogwash. No one is expecting the riders to do it faster than before. Races like the Tour are meant to be so long that a large part of the field doesn’t make it to Paris. Finishing the whole Tour is supposed to be as prestigious as wearing the yellow jersey but the cyclists who dope would have us think otherwise. I say any doper who gets caught should get a lifetime ban from the sport. Simple, objective, ultimate. Clean the sport out; there are plenty of others out there to fill the holes.
Had a great ride today; felt like I was on top of my form the whole time and was able to keep up a 17mph average for most the trip. I slowed during a few of the ascents, but this is pretty normal of course. I ended up doing 18 miles total and definately could have gone farther had there been more sunlight.
So to celebrate, I installed Diablo II and quickly got my Paladin to level 4 which of course means getting the Cold Plains waypoint! Man this game is addicting; I can’t wait until Diablo III comes out and consumes my life.
Ever go out on a run, or in this case a ride, and quickly come to the realization that you are just not in it enough to finish what you have set out to do? Today I wanted to tackle at least 40 miles. The last time I did this I was feeling great until about mile 32 when my right calf suddenly locked up on me. This time I hit the first hill but already knew that today was just not my day. I decided to stick with it and go as long as I could stand which I knew would be at least 16 miles more than the 6 I had already traveled. I ended up at around 28 miles which isn’t too bad for me. My muscles are barely tired but my right knee is hurting quite a bit.
I think something is up with the bike because it just doesn’t feel right anymore. After the two falls I had two weeks ago, something is rubbing and making it quite a bit more difficult to pedal. The only problem is that I can’t seem to figure out what the problem is and can only say it is coming from the rear. Hopefully a new bike will be bought soon enough that I do not have to put up with the problems of a 20 year old bike anymore.
One more thought… Yesterday I got new riding shorts, ditching the hand me downs as well as my underwear. The new shorts feel great and the long ride felt fine on everything down in that area. Much better than riding with underwear and a ripped up chamois pad. I was a little iffy about going “commando” but after wearing the shorts around the house for an hour or so I realized how great they were.
Today I bring you more of the same! Well, not quite, but today’s post is about navigation. Having covered the left / quick launch navigation, I decided it was time to tackle the top navigation. Reasons? Drop down menus are definately nice, and I think there is a possibility to again get away from tables while adding some nice styling and better functionality. Enter javascript!
Step 1: Get this JavaScript menu (.js) and put it into “C:\…\12\TEMPLATE\LAYOUTS\1033\”
Step 2: Time to get Visual Studio open again, remember that menu we made for the left hand side navigation? Well we can use the same class and reconfigure it a bit for the top nav. This code adds some extra functionality that I will cover in a step or two. Once you are done creating the class, follow the same steps mention in the 4th installment of this series to get the navigation control installed. Read the rest of this entry »
Michael O’Donovan brings us a blog post about custom (left) navigation in SharePoint. That is what I will be tackling today so I can move away from the ugly Tables and use a more common UL/LI scheme.
Here is my class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | using System; using System.Collections; using System.Globalization; using System.ComponentModel; using System.Security.Permissions; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Xml; using System.Xml.XPath; using Microsoft.SharePoint.Utilities; namespace MMOinsite.SharePoint.Components { [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public class ListNavigation : HierarchicalDataBoundControl { private XmlDocument navigationTree; private string currentNodeKey = string.Empty; private string linkClass = "NavLeftLink"; private string listItemClass = "NavLeftListItem"; private string listClass = "NavLeftList"; private string linkSelectedClass = "NavLeftListItemSelected"; private bool appendLevel = false; private string appendLevelClass = "NavLeftListItem"; protected override void PerformDataBinding() { base.PerformDataBinding(); // Oh god, no data source! ABORT! if (!IsBoundUsingDataSourceID && (DataSource == null)) return; HierarchicalDataSourceView view = GetData(""); if (view == null) throw new InvalidOperationException("Cannot get any data from the data source control."); IHierarchicalEnumerable enumerable = view.Select(); if (enumerable != null) { navigationTree = new XmlDocument(); navigationTree.LoadXml("<nodes></nodes>"); try { AddNavigationItem(navigationTree.DocumentElement, enumerable, 1); } finally { } ViewState["navXml"] = navigationTree.OuterXml; } } private void AddNavigationItem(XmlElement currentNode, IHierarchicalEnumerable enumerable, int depth) { foreach (object item in enumerable) { IHierarchyData data = enumerable.GetHierarchyData(item); NavigationItem navItem = BuildNavigationItem(data, depth); XmlElement newNavElement = BuildNavigationNode(currentNode, navItem); currentNode.AppendChild(newNavElement); if(data.HasChildren) { IHierarchicalEnumerable newEnumerable = data.GetChildren(); if(newEnumerable != null) AddNavigationItem(newNavElement, newEnumerable, depth + 1); } } } private NavigationItem BuildNavigationItem(IHierarchyData data, int depth) { NavigationItem tmpNavItem = new NavigationItem(); try { INavigateUIData navNode = (INavigateUIData)data; tmpNavItem.Title = navNode.Value; tmpNavItem.Url = navNode.NavigateUrl; tmpNavItem.Level = depth; if (currentNodeKey.Length == 0) { SiteMapDataSource dataSource = GetDataSource() as SiteMapDataSource; if (dataSource != null) if (dataSource.Provider.CurrentNode != null) currentNodeKey = dataSource.Provider.CurrentNode.Url.ToLower(); } if (string.Compare(tmpNavItem.Url, currentNodeKey, true, CultureInfo.InvariantCulture) == 0) tmpNavItem.Selected = true; } catch (Exception ex) { throw ex; } return tmpNavItem; } private NavigationItem BuildNavigationItem(XmlNode node) { NavigationItem tmpNavItem = new NavigationItem(); tmpNavItem.Title = node.Attributes["title"].InnerText; tmpNavItem.Url = node.Attributes["url"].InnerText; tmpNavItem.Selected = Convert.ToBoolean(node.Attributes["isSelected"].InnerText); tmpNavItem.Level = Convert.ToInt32(node.Attributes["level"].InnerText); return tmpNavItem; } private XmlElement BuildNavigationNode(XmlElement parentNode, NavigationItem navItem) { XmlElement tmpNode = navigationTree.CreateElement("node"); tmpNode.SetAttribute("url", navItem.Url); tmpNode.SetAttribute("title", navItem.Title); tmpNode.SetAttribute("level", navItem.Level.ToString()); tmpNode.SetAttribute("isSelected", navItem.Selected.ToString()); return tmpNode; } protected override void Render(HtmlTextWriter writer) { if (navigationTree == null && ViewState["navXml"] != null) { navigationTree = new XmlDocument(); navigationTree.LoadXml(ViewState["navXml"].ToString()); } XmlNodeList nodeList = navigationTree.SelectNodes("nodes/node"); if (nodeList.Count > 0) { WriteListStart(writer); foreach (XmlNode node in nodeList) { Render(node, writer); } WriteListEnd(writer); } } protected virtual void WriteListStart(HtmlTextWriter writer) { writer.Write(string.Format("<ul class=\"{0}\">", ListClass)); } protected virtual void WriteListEnd(HtmlTextWriter writer) { writer.Write("</ul>"); } protected virtual void Render(XmlNode navNode, HtmlTextWriter writer) { NavigationItem navItem = BuildNavigationItem(navNode); writer.Write( string.Format( "<li class=\"{0}{1}\">", ListItemClass, (AppendLevel) ? string.Format(" {0}{1}", AppendLevelClass, navItem.Level) : "" ) ); writer.Write( string.Format( "<a class=\"{0}\" href=\"{1}\">{2}</a>", (navItem.Selected) ? LinkSelectedClass : LinkClass, navItem.Url, navItem.Title ) ); if (navNode.ChildNodes.Count > 0) { WriteListStart(writer); XmlNodeList nodeList = navNode.SelectNodes("node"); foreach (XmlNode childNode in nodeList) Render(childNode, writer); WriteListEnd(writer); } writer.Write("</li>"); } public string ListClass { get { return listClass; } set { listClass = value; } } public string LinkSelectedClass { get { return linkSelectedClass; } set { linkSelectedClass = value; } } public string LinkClass { get { return linkClass; } set { linkClass = value; } } public string ListItemClass { get { return listItemClass; } set { listItemClass = value; } } public bool AppendLevel { get { return appendLevel; } set { appendLevel = value; } } public string AppendLevelClass { get { return appendLevelClass; } set { appendLevelClass = value; } } } } |
But how do we install it? Good question John. Why thank you John! Copy it to your server. Open the GAC (C:\WINDOWS\assembly) and drag and drop. Now perform an IISRESET and add the control to your master page in the usual way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <%@ Register Tagprefix="asp" Namespace="MMOinsite.SharePoint.Components" Assembly="MMOinsite.SharePoint.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=abb33cdce6ddaae1" %>
...
<Sharepoint:SPNavigationManager id="QuickLaunchNavigationManager"
runat="server"
QuickLaunchControlId="QuickLaunchMenu"
ContainedControl="QuickLaunch"
EnableViewState="false" >
<div>
<SharePoint:DelegateControl runat="server" ControlId="QuickLaunchDataSource">
<Template_Controls>
<asp:SiteMapDataSource
SiteMapProvider="SPNavigationProvider"
ShowStartingNode="False"
id="QuickLaunchSiteMap"
StartingNodeUrl="sid:1025"
runat="server"
/>
</Template_Controls>
</SharePoint:DelegateControl>
<asp:ListNavigation id="CustomListNavigation" DataSourceId="QuickLaunchSiteMap" runat="server" />
</div>
</SharePoint:SPNavigationManager> |
It is important to note that the UL/LI scheme is incredibly flexible. You can make them horizontal, drop down menus or keep them as standard vertical lists. Once the control is in place, the designer (CSS for the win here) can take over. For this reason, this type of navigation scheme can also make its way to the top navigation bar. But I will leave that up to you as I have got to get back to work!
Update (9:58): Here are the CSS styles I use with setting AppendLevel to true in the control tag of the master page. There is some pretty wacky CSS going on here and I am sure it can be cleaned up, but it works in IE7 and is a good place to start.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | .NavLeftLink{
color: #2D2D2D;
}
.NavLeftListItem{
background: #F2F8FF;
margin-left: 0px;
padding: 0px;
width: 100%;
}
.NavLeftListItem2{
}
.NavLeftListItem a{
padding: 2px 0px 2px 5px;
border-top: solid 1px #25475A;
width: 100%;
}
.NavLeftListItem a:hover{
background: #D4F7B9;
}
.NavLeftListItem1 a{
background: #BACCD6;
font-size: 1.2em;
font-weight: bold;
border-bottom: solid 1px #25475A;
margin-bottom: 1px;
}
.NavLeftListItem2 a{
background: #F2F8FF;
border: 0px;
padding-left: 20px;
font-size: 1em;
font-weight: normal;
background-image: url(/_layouts/images/navBullet.gif);
background-repeat: no-repeat;
background-position: 5px top;
}
.NavLeftListItem2 a:hover{
background-image: url(/_layouts/images/navBullet.gif);
background-repeat: no-repeat;
background-position: 5px top;
}
.NavLeftListItemSelected{
background: #D4F7B9;
}
.NavLeftList{
margin-top: 0px;
margin-left: 0px;
list-style: none;
border-bottom: solid 1px #25475A;
}
.NavLeftList .NavLeftList{
border: 0px;
} |
Wow. What an amazing writer. Read the David Millar Diaries.