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.
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
| 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 DropDownNavigation : HierarchicalDataBoundControl
{
private XmlDocument navigationTree;
private string currentNodeKey = string.Empty;
private string linkClass = "underline";
private string listItemClass = "";
private string listClass = "";
private string linkSelectedClass = "";
private bool appendLevel = false;
private string appendLevelClass = "";
int counter = 1;
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)
{
counter = 1;
foreach (XmlNode node in nodeList)
{
RenderOne(node, writer);
foreach(XmlNode subNode in node.SelectNodes("node"))
Render(subNode, writer, true);
}
}
}
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 RenderOne(XmlNode navNode, HtmlTextWriter writer)
{
NavigationItem navItem = BuildNavigationItem(navNode);
writer.Write("<dl class=\"dropdown\">");
writer.Write("<dt id=\"" + counter.ToString() + "-ddheader\">");
writer.Write(
string.Format(
"<a class=\"{0}\" href=\"{1}\">{2}</a>",
(navItem.Selected) ? LinkSelectedClass : LinkClass,
navItem.Url,
navItem.Title
)
);
writer.Write("<dd id=\"" + counter.ToString() + "-ddcontent\">");
writer.Write("</dd>");
writer.Write("</dt>");
writer.Write("</dl>");
counter++;
}
protected virtual void Render(XmlNode navNode, HtmlTextWriter writer, bool isHeader)
{
NavigationItem navItem = BuildNavigationItem(navNode);
string navItemDivId = navItem.Title.Replace(" ", "-") + "ImgDiv";
if (isHeader)
{
writer.Write("<dl class=\"dropdown\">");
writer.Write("<dt id=\"" + counter.ToString() + "-ddheader\" ");
if(navNode.ChildNodes.Count > 0)
writer.Write("onmouseover=\"ddMenu('" + counter.ToString() + "',1)\" onmouseout=\"ddMenu('" + counter.ToString() + "',-1)\"");
writer.Write(">");
writer.Write(
string.Format(
"<a class=\"{0}\" href=\"{1}\" onmouseover=\"RollOut('{3}');\" onmouseout=\"RollIn('{3}');\">{2}</a>",
(navItem.Selected) ? LinkSelectedClass : LinkClass,
navItem.Url,
navItem.Title,
navItemDivId
)
);
writer.Write("</dt>");
writer.Write("<dd id=\"" + counter.ToString() + "-ddcontent\" ");
if (navNode.ChildNodes.Count > 0)
writer.Write("onmouseover=\"cancelHide('" + counter.ToString() + "')\" onmouseout=\"ddMenu('" + counter.ToString() + "',-1)\"");
writer.Write(">");
counter++;
}
else
{
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}\" onmouseover=\"RollOut('{3}');\" onmouseout=\"RollIn('{3}');\">{2}</a>",
(navItem.Selected) ? LinkSelectedClass : LinkClass,
navItem.Url,
navItem.Title,
navItemDivId
)
);
}
if (navNode.ChildNodes.Count > 0 && isHeader)
{
WriteListStart(writer);
XmlNodeList nodeList = navNode.SelectNodes("node");
foreach (XmlNode childNode in nodeList)
Render(childNode, writer, false);
WriteListEnd(writer);
}
if (isHeader)
{
writer.Write("</dd>");
writer.Write("</dl>");
}
else
{
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; }
}
}
} |
Step 3: We need to add the styles to our ever-growing CSS file! Here they are.
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
| .dropdown {
float: left;
}
.dropdown dt {
width: 150px;
height: 22px;
border: 0px solid #000;
padding: 0px;
font-weight: bold;
cursor: pointer;
text-align: center;
}
.dropdown a{
color:white;
}
.dropdown dt:hover {
background: url('/_layouts/images/topnavhover.gif');
}
.dropdown dd {
position: absolute;
overflow: hidden;
margin-top: 0px;
margin-left: 0px;
width: 170px;
height: 22px;
display: none;
background: #fff;
z-index: 200;
opacity: 0;
border: 1px solid #25475A;
background: #DAE8EF;
border-top: 0px;
}
.dropdown ul {
margin: 0px;
width: 170px;
list-style: none;
border-top: none;
}
.dropdown li {
display: inline;
text-align: left;
}
.dropdown a, .dropdown a:active, .dropdown a:visited {
font-size: 0.8em;
padding: 2px;
padding-top: 3px;
display: block;
color: #2D2D2D;
font-weight: bold;
text-decoration: none;
width: 100%;
}
.dropdown a:hover {
/*background: #7BC143;*/
text-decoration: underline;
color: #000;
}
.dropdown .underline {
} |
Step 4: Now what was that extra functionality? Well for our SharePoint site I have created an image slide animation that slides out from the top nav. This is so when users hover over the various departments, we can show some images about what the departments do in the whitespace of the site. Here is rollover.js, which again we put in the same directory as the other js file.
The code is a modified version of the previous menu code to include resizing the margin instead of just the height. This will force the div to slide up rather than down which is what we want. I have also modified it to include a hack (currh < 20 instead of < 2) to make sure the div is hidden.
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
| var timerLen = 15;
var slideSpeed = 5;
function Roll(divId, dir)
{
var d = document.getElementById(divId);
if(d == null)
return;
clearInterval(d.timer);
if(dir == 1){
if(d.maxh && d.maxh <= d.offsetHeight)
return;
else if(!d.maxh){
d.style.height = 'auto';
d.maxh = 100;
d.style.height = '0px';
}
d.style.display = 'block';
d.timer = setInterval(function(){DoSlide(d, 1)}, timerLen);
}
else{
d.timer = setInterval(function(){DoSlide(d,-1)}, timerLen);
}
}
function DoSlideIn(d){
d.timer = setInterval(function(){DoSlide(d,-1)}, timerLen);
}
function DoSlide(d,dir)
{
var currh = d.offsetHeight;
var dist;
if(dir == 1)
dist = ((d.maxh - currh) / slideSpeed);
else
dist = (currh / slideSpeed);
if(dist <= 1 && dir == 1)
dist = 1;
d.style.height = currh + (dist * dir) + 'px';
d.style.opacity = currh / d.maxh;
d.style.marginTop = 100 - (currh * 100 / d.maxh) + 'px';
d.style.filter = 'alpha(opacity=' + (currh * 100 / d.maxh) + ')';
if((currh < 20 && dir != 1) || (currh > (d.maxh - 2) && dir == 1)){
clearInterval(d.timer);
if(dir != 1){
d.style.marginTop = 100;
d.style.display = 'none';
}
}
}
function RollOut(divId)
{
Roll(divId, 1);
}
function RollIn(divId)
{
Roll(divId, -1);
} |
Step 5: Now that we have the code setup, we need to add the controls and js files to the masterpage! First we need the javascript files. I was having trouble with the second, but a manual include worked.
1
2
| <SharePoint:ScriptLink language="javascript" name="dropdown.js" Defer="true" runat="server"/>
<script type="text/javascript" language="javascript" src="/_layouts/1033/rollover.js"> |
Next we need the divs for the images that slide out. This piece is optional.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <!-- BEGIN: IMAGE DIVS -->
<div id="ImageDivContainer">
<div style="background-image:url('/images/departments/Accounting.png');" id="AccountingImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="LossImgDiv"> </div>
<div style="background-image:url('/images/departments/HumanResources.png');" id="Human-ResourcesImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="Information-TechnologyImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="ReinsuranceImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="UnderwritingImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="CollectionsImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="General-CounselImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="ManagementImgDiv"> </div>
<div style="background-image:url('/images/departments/Loss.png');" id="Underwriting-SupportImgDiv"> </div>
</div>
<!-- END: IMAGE DIVS --> |
Next, under PlaceHolderGlobalNavigation, we put our custom control and remove the SharePoint:AspMenu.
1
| <asp:DropDownNavigation id="CustomTopListNavigation" DataSourceId="topSiteMap" runat="server" AppendLevel="false" /> |
And finally, we add the styles for the image divs into our CSS file. Again, this is not required.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #ImageDivContainer{
position:relative;
float: right;
/*right:5%;
top:35px;*/
margin-right: -4px;
overflow:hidden;
width:550px;
height:100px;
vertical-align:bottom;
}
#ImageDivContainer div{
position:absolute;
right:0;
display:none;
width:550px;
height:100px;
z-index: 200;
opacity: 0;
margin-top: 100px;
margin-left: 0px;
} |
This entry was posted
on Friday, July 11th, 2008 at 12:32 pm and is filed under General.
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.
Leave a Reply