3 // Lluis Sanchez Gual (lluis@novell.com)
4 // Igor Zelmanovich (igorz@mainsoft.com)
5 // Marek Habersack <grendel@twistedcode.net>
7 // (C) 2010 Novell, Inc (http://novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections.Generic;
35 using System.Web.UI.HtmlControls;
37 namespace System.Web.UI.WebControls
39 sealed class MenuTableRenderer : BaseMenuRenderer
41 const string onPreRenderScript = "var {0} = new Object ();\n{0}.webForm = {1};\n{0}.disappearAfter = {2};\n{0}.vertical = {3};";
43 public override HtmlTextWriterTag Tag {
44 get { return HtmlTextWriterTag.Table; }
48 public MenuTableRenderer (Menu owner)
53 public override void AddAttributesToRender (HtmlTextWriter writer)
55 writer.AddAttribute ("cellpadding", "0", false);
56 writer.AddAttribute ("cellspacing", "0", false);
57 writer.AddAttribute ("border", "0", false);
59 base.AddAttributesToRender (writer);
62 public override void PreRender (Page page, HtmlHead head, ClientScriptManager csm, string cmenu, StringBuilder script)
65 MenuItemStyle staticMenuItemStyle = owner.StaticMenuItemStyleInternal;
66 SubMenuStyle staticMenuStyle = owner.StaticMenuStyleInternal;
67 MenuItemStyle dynamicMenuItemStyle = owner.DynamicMenuItemStyleInternal;
68 SubMenuStyle dynamicMenuStyle = owner.DynamicMenuStyleInternal;
69 MenuItemStyleCollection levelMenuItemStyles = owner.LevelMenuItemStyles;
70 List<Style> levelMenuItemLinkStyles = owner.LevelMenuItemLinkStyles;
71 SubMenuStyleCollection levelSubMenuStyles = owner.LevelSubMenuStylesInternal;
72 MenuItemStyle staticSelectedStyle = owner.StaticSelectedStyleInternal;
73 MenuItemStyle dynamicSelectedStyle = owner.DynamicSelectedStyleInternal;
74 MenuItemStyleCollection levelSelectedStyles = owner.LevelSelectedStylesInternal;
75 List<Style> levelSelectedLinkStyles = owner.LevelSelectedLinkStyles;
76 Style staticHoverStyle = owner.StaticHoverStyleInternal;
77 Style dynamicHoverStyle = owner.DynamicHoverStyleInternal;
79 if (!csm.IsClientScriptIncludeRegistered (typeof (Menu), "Menu.js")) {
80 string url = csm.GetWebResourceUrl (typeof (Menu), "Menu.js");
81 csm.RegisterClientScriptInclude (typeof (Menu), "Menu.js", url);
84 script.AppendFormat (onPreRenderScript,
86 page.IsMultiForm ? page.theForm : "window",
87 ClientScriptManager.GetScriptLiteral (owner.DisappearAfter),
88 ClientScriptManager.GetScriptLiteral (owner.Orientation == Orientation.Vertical));
90 if (owner.DynamicHorizontalOffset != 0)
91 script.Append (String.Concat (cmenu, ".dho = ", ClientScriptManager.GetScriptLiteral (owner.DynamicHorizontalOffset), ";\n"));
92 if (owner.DynamicVerticalOffset != 0)
93 script.Append (String.Concat (cmenu, ".dvo = ", ClientScriptManager.GetScriptLiteral (owner.DynamicVerticalOffset), ";\n"));
95 // The order in which styles are defined matters when more than one class
96 // is assigned to an element
97 RegisterStyle (owner.PopOutBoxStyle, head);
98 RegisterStyle (owner.ControlStyle, owner.ControlLinkStyle, head);
100 if (staticMenuItemStyle != null)
101 RegisterStyle (owner.StaticMenuItemStyle, owner.StaticMenuItemLinkStyle, head);
103 if (staticMenuStyle != null)
104 RegisterStyle (owner.StaticMenuStyle, head);
106 if (dynamicMenuItemStyle != null)
107 RegisterStyle (owner.DynamicMenuItemStyle, owner.DynamicMenuItemLinkStyle, head);
109 if (dynamicMenuStyle != null)
110 RegisterStyle (owner.DynamicMenuStyle, head);
112 if (levelMenuItemStyles != null && levelMenuItemStyles.Count > 0) {
113 levelMenuItemLinkStyles = new List<Style> (levelMenuItemStyles.Count);
114 foreach (Style style in levelMenuItemStyles) {
115 Style linkStyle = new Style ();
116 levelMenuItemLinkStyles.Add (linkStyle);
117 RegisterStyle (style, linkStyle, head);
121 if (levelSubMenuStyles != null)
122 foreach (Style style in levelSubMenuStyles)
123 RegisterStyle (style, head);
125 if (staticSelectedStyle != null)
126 RegisterStyle (staticSelectedStyle, owner.StaticSelectedLinkStyle, head);
128 if (dynamicSelectedStyle != null)
129 RegisterStyle (dynamicSelectedStyle, owner.DynamicSelectedLinkStyle, head);
131 if (levelSelectedStyles != null && levelSelectedStyles.Count > 0) {
132 levelSelectedLinkStyles = new List<Style> (levelSelectedStyles.Count);
133 foreach (Style style in levelSelectedStyles) {
134 Style linkStyle = new Style ();
135 levelSelectedLinkStyles.Add (linkStyle);
136 RegisterStyle (style, linkStyle, head);
140 if (staticHoverStyle != null) {
142 throw new InvalidOperationException ("Using Menu.StaticHoverStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
143 RegisterStyle (staticHoverStyle, owner.StaticHoverLinkStyle, head);
144 script.Append (String.Concat (cmenu, ".staticHover = ", ClientScriptManager.GetScriptLiteral (staticHoverStyle.RegisteredCssClass), ";\n"));
145 script.Append (String.Concat (cmenu, ".staticLinkHover = ", ClientScriptManager.GetScriptLiteral (owner.StaticHoverLinkStyle.RegisteredCssClass), ";\n"));
148 if (dynamicHoverStyle != null) {
150 throw new InvalidOperationException ("Using Menu.DynamicHoverStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
151 RegisterStyle (dynamicHoverStyle, owner.DynamicHoverLinkStyle, head);
152 script.Append (String.Concat (cmenu, ".dynamicHover = ", ClientScriptManager.GetScriptLiteral (dynamicHoverStyle.RegisteredCssClass), ";\n"));
153 script.Append (String.Concat (cmenu, ".dynamicLinkHover = ", ClientScriptManager.GetScriptLiteral (owner.DynamicHoverLinkStyle.RegisteredCssClass), ";\n"));
157 public override void RenderBeginTag (HtmlTextWriter writer, string skipLinkText)
161 // <a href="#ID_SkipLink">
162 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + owner.ClientID + "_SkipLink");
163 writer.RenderBeginTag (HtmlTextWriterTag.A);
165 // <img alt="" height="0" width="0" src="" style="border-width:0px;"/>
166 writer.AddAttribute (HtmlTextWriterAttribute.Alt, skipLinkText);
167 writer.AddAttribute (HtmlTextWriterAttribute.Height, "0");
168 writer.AddAttribute (HtmlTextWriterAttribute.Width, "0");
170 Page page = owner.Page;
171 ClientScriptManager csm = page != null ? page.ClientScript : new ClientScriptManager (null);
173 writer.AddAttribute (HtmlTextWriterAttribute.Src, csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif"));
174 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0px");
175 writer.RenderBeginTag (HtmlTextWriterTag.Img);
176 writer.RenderEndTag ();
178 writer.RenderEndTag (); // </a>
181 public override void RenderEndTag (HtmlTextWriter writer)
184 if (owner.StaticDisplayLevels == 1 && owner.MaximumDynamicDisplayLevels > 0)
185 owner.RenderDynamicMenu (writer, owner.Items);
188 public override void RenderContents (HtmlTextWriter writer)
191 RenderMenuBody (writer, owner.Items, owner.Orientation == Orientation.Vertical, false, false);
194 void RenderMenuBeginTagAttributes (HtmlTextWriter writer, bool dynamic, int menuLevel)
196 writer.AddAttribute ("cellpadding", "0", false);
197 writer.AddAttribute ("cellspacing", "0", false);
198 writer.AddAttribute ("border", "0", false);
201 SubMenuStyle style = new SubMenuStyle ();
202 FillMenuStyle (null, dynamic, menuLevel, style);
203 style.AddAttributesToRender (writer);
207 public override void RenderMenuBeginTag (HtmlTextWriter writer, bool dynamic, int menuLevel)
209 RenderMenuBeginTagAttributes (writer, dynamic, menuLevel);
210 writer.RenderBeginTag (HtmlTextWriterTag.Table);
213 void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing, bool vertical)
216 writer.AddStyleAttribute ("height", itemSpacing.ToString ());
217 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
218 writer.RenderBeginTag (HtmlTextWriterTag.Td);
219 writer.RenderEndTag ();
220 writer.RenderEndTag ();
222 writer.AddStyleAttribute ("width", itemSpacing.ToString ());
223 writer.RenderBeginTag (HtmlTextWriterTag.Td);
224 writer.RenderEndTag ();
228 public override void RenderMenuBody (HtmlTextWriter writer, MenuItemCollection items, bool vertical, bool dynamic, bool notLast)
232 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
234 int count = items.Count;
235 var oc = new OwnerContext (this);
237 for (int n = 0; n < count; n++) {
238 MenuItem item = items [n];
239 Adapters.MenuAdapter adapter = owner.Adapter as Adapters.MenuAdapter;
241 adapter.RenderItem (writer, item, n);
243 RenderMenuItem (writer, item, vertical, (n + 1) == count ? notLast : true, n == 0, oc);
247 writer.RenderEndTag (); // TR
250 protected override void RenderMenuItem (HtmlTextWriter writer, MenuItem item, bool vertical, bool notLast, bool isFirst, OwnerContext oc)
253 string clientID = oc.ClientID;
254 bool displayChildren = owner.DisplayChildren (item);
255 bool dynamicChildren = displayChildren && (item.Depth + 1 >= oc.StaticDisplayLevels);
256 bool isDynamicItem = IsDynamicItem (owner, item);
257 bool isVertical = oc.IsVertical || isDynamicItem;
258 Unit itemSpacing = owner.GetItemSpacing (item, isDynamicItem);
260 if (itemSpacing != Unit.Empty && (item.Depth > 0 || !isFirst))
261 RenderMenuItemSpacing (writer, itemSpacing, isVertical);
263 if(!String.IsNullOrEmpty(item.ToolTip))
264 writer.AddAttribute (HtmlTextWriterAttribute.Title, item.ToolTip);
266 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
268 string parentId = isDynamicItem ? "'" + item.Parent.Path + "'" : "null";
269 if (dynamicChildren) {
270 writer.AddAttribute ("onmouseover",
271 "javascript:Menu_OverItem ('" + clientID + "','" + item.Path + "'," + parentId + ")");
272 writer.AddAttribute ("onmouseout",
273 "javascript:Menu_OutItem ('" + clientID + "','" + item.Path + "')");
274 } else if (isDynamicItem) {
275 writer.AddAttribute ("onmouseover",
276 "javascript:Menu_OverDynamicLeafItem ('" + clientID + "','" + item.Path + "'," + parentId + ")");
277 writer.AddAttribute ("onmouseout",
278 "javascript:Menu_OutItem ('" + clientID + "','" + item.Path + "'," + parentId + ")");
280 writer.AddAttribute ("onmouseover",
281 "javascript:Menu_OverStaticLeafItem ('" + clientID + "','" + item.Path + "')");
282 writer.AddAttribute ("onmouseout",
283 "javascript:Menu_OutItem ('" + clientID + "','" + item.Path + "')");
286 writer.RenderBeginTag (HtmlTextWriterTag.Td);
288 // Top separator image
291 RenderSeparatorImage (owner, writer, oc.DynamicTopSeparatorImageUrl, false);
293 RenderSeparatorImage (owner, writer, oc.StaticTopSeparatorImageUrl, false);
297 MenuItemStyle style = new MenuItemStyle ();
299 if (oc.Header != null) {
300 // styles are registered
301 if (!isDynamicItem && oc.StaticMenuItemStyle != null) {
302 AddCssClass (style, oc.StaticMenuItemStyle.CssClass);
303 AddCssClass (style, oc.StaticMenuItemStyle.RegisteredCssClass);
305 if (isDynamicItem && oc.DynamicMenuItemStyle != null) {
306 AddCssClass (style, oc.DynamicMenuItemStyle.CssClass);
307 AddCssClass (style, oc.DynamicMenuItemStyle.RegisteredCssClass);
309 if (oc.LevelMenuItemStyles != null && oc.LevelMenuItemStyles.Count > item.Depth) {
310 AddCssClass (style, oc.LevelMenuItemStyles [item.Depth].CssClass);
311 AddCssClass (style, oc.LevelMenuItemStyles [item.Depth].RegisteredCssClass);
313 if (item == oc.SelectedItem) {
314 if (!isDynamicItem && oc.StaticSelectedStyle != null) {
315 AddCssClass (style, oc.StaticSelectedStyle.CssClass);
316 AddCssClass (style, oc.StaticSelectedStyle.RegisteredCssClass);
318 if (isDynamicItem && oc.DynamicSelectedStyle != null) {
319 AddCssClass (style, oc.DynamicSelectedStyle.CssClass);
320 AddCssClass (style, oc.DynamicSelectedStyle.RegisteredCssClass);
322 if (oc.LevelSelectedStyles != null && oc.LevelSelectedStyles.Count > item.Depth) {
323 AddCssClass (style, oc.LevelSelectedStyles [item.Depth].CssClass);
324 AddCssClass (style, oc.LevelSelectedStyles [item.Depth].RegisteredCssClass);
328 // styles are not registered
329 if (!isDynamicItem && oc.StaticMenuItemStyle != null)
330 style.CopyFrom (oc.StaticMenuItemStyle);
331 if (isDynamicItem && oc.DynamicMenuItemStyle != null)
332 style.CopyFrom (oc.DynamicMenuItemStyle);
333 if (oc.LevelMenuItemStyles != null && oc.LevelMenuItemStyles.Count > item.Depth)
334 style.CopyFrom (oc.LevelMenuItemStyles [item.Depth]);
335 if (item == oc.SelectedItem) {
336 if (!isDynamicItem && oc.StaticSelectedStyle != null)
337 style.CopyFrom (oc.StaticSelectedStyle);
338 if (isDynamicItem && oc.DynamicSelectedStyle != null)
339 style.CopyFrom (oc.DynamicSelectedStyle);
340 if (oc.LevelSelectedStyles != null && oc.LevelSelectedStyles.Count > item.Depth)
341 style.CopyFrom (oc.LevelSelectedStyles [item.Depth]);
344 style.AddAttributesToRender (writer);
346 writer.AddAttribute ("id", GetItemClientId (clientID, item, "i"));
347 writer.AddAttribute ("cellpadding", "0", false);
348 writer.AddAttribute ("cellspacing", "0", false);
349 writer.AddAttribute ("border", "0", false);
350 writer.AddAttribute ("width", "100%", false);
351 writer.RenderBeginTag (HtmlTextWriterTag.Table);
352 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
357 writer.AddStyleAttribute (HtmlTextWriterStyle.Width, "100%");
359 writer.AddStyleAttribute ("white-space", "nowrap");
360 writer.RenderBeginTag (HtmlTextWriterTag.Td);
362 RenderItemHref (owner, writer, item);
364 Style linkStyle = new Style ();
365 if (oc.Header != null) {
366 // styles are registered
367 AddCssClass (linkStyle, oc.ControlLinkStyle.RegisteredCssClass);
369 if (!isDynamicItem && oc.StaticMenuItemStyle != null) {
370 AddCssClass (linkStyle, oc.StaticMenuItemStyle.CssClass);
371 AddCssClass (linkStyle, oc.StaticMenuItemLinkStyle.RegisteredCssClass);
373 if (isDynamicItem && oc.DynamicMenuItemStyle != null) {
374 AddCssClass (linkStyle, oc.DynamicMenuItemStyle.CssClass);
375 AddCssClass (linkStyle, oc.DynamicMenuItemLinkStyle.RegisteredCssClass);
377 if (oc.LevelMenuItemStyles != null && oc.LevelMenuItemStyles.Count > item.Depth) {
378 AddCssClass (linkStyle, oc.LevelMenuItemStyles [item.Depth].CssClass);
379 AddCssClass (linkStyle, oc.LevelMenuItemLinkStyles [item.Depth].RegisteredCssClass);
381 if (item == oc.SelectedItem) {
382 if (!isDynamicItem && oc.StaticSelectedStyle != null) {
383 AddCssClass (linkStyle, oc.StaticSelectedStyle.CssClass);
384 AddCssClass (linkStyle, oc.StaticSelectedLinkStyle.RegisteredCssClass);
386 if (isDynamicItem && oc.DynamicSelectedStyle != null) {
387 AddCssClass (linkStyle, oc.DynamicSelectedStyle.CssClass);
388 AddCssClass (linkStyle, oc.DynamicSelectedLinkStyle.RegisteredCssClass);
390 if (oc.LevelSelectedStyles != null && oc.LevelSelectedStyles.Count > item.Depth) {
391 AddCssClass (linkStyle, oc.LevelSelectedStyles [item.Depth].CssClass);
392 AddCssClass (linkStyle, oc.LevelSelectedLinkStyles [item.Depth].RegisteredCssClass);
396 // styles are not registered
397 linkStyle.CopyFrom (oc.ControlLinkStyle);
399 if (!isDynamicItem && oc.StaticMenuItemStyle != null)
400 linkStyle.CopyFrom (oc.StaticMenuItemLinkStyle);
401 if (isDynamicItem && oc.DynamicMenuItemStyle != null)
402 linkStyle.CopyFrom (oc.DynamicMenuItemLinkStyle);
403 if (oc.LevelMenuItemStyles != null && oc.LevelMenuItemStyles.Count > item.Depth)
404 linkStyle.CopyFrom (oc.LevelMenuItemLinkStyles [item.Depth]);
405 if (item == oc.SelectedItem) {
406 if (!isDynamicItem && oc.StaticSelectedStyle != null)
407 linkStyle.CopyFrom (oc.StaticSelectedLinkStyle);
408 if (isDynamicItem && oc.DynamicSelectedStyle != null)
409 linkStyle.CopyFrom (oc.DynamicSelectedLinkStyle);
410 if (oc.LevelSelectedStyles != null && oc.LevelSelectedStyles.Count > item.Depth)
411 linkStyle.CopyFrom (oc.LevelSelectedLinkStyles [item.Depth]);
414 linkStyle.AlwaysRenderTextDecoration = true;
416 linkStyle.AddAttributesToRender (writer);
418 writer.AddAttribute ("id", GetItemClientId (clientID, item, "l"));
420 if (item.Depth > 0 && !isDynamicItem) {
422 Unit unit = oc.StaticSubMenuIndent;
423 if (unit == Unit.Empty)
427 Unit indent = new Unit (value * item.Depth, oc.StaticSubMenuIndent.Type);
428 writer.AddStyleAttribute (HtmlTextWriterStyle.MarginLeft, indent.ToString ());
430 writer.RenderBeginTag (HtmlTextWriterTag.A);
431 owner.RenderItemContent (writer, item, isDynamicItem);
432 writer.RenderEndTag (); // A
434 writer.RenderEndTag (); // TD
438 if (dynamicChildren) {
439 string popOutImage = GetPopOutImage (owner, item, isDynamicItem);
440 if (popOutImage != null) {
441 writer.RenderBeginTag (HtmlTextWriterTag.Td);
442 writer.AddAttribute ("src", owner.ResolveClientUrl (popOutImage));
443 writer.AddAttribute ("border", "0");
444 string toolTip = String.Format (isDynamicItem ? oc.DynamicPopOutImageTextFormatString : oc.StaticPopOutImageTextFormatString, item.Text);
445 writer.AddAttribute (HtmlTextWriterAttribute.Alt, toolTip);
446 writer.RenderBeginTag (HtmlTextWriterTag.Img);
447 writer.RenderEndTag (); // IMG
448 writer.RenderEndTag (); // TD
452 writer.RenderEndTag (); // TR
453 writer.RenderEndTag (); // TABLE
455 writer.RenderEndTag (); // TD
457 if (!isVertical && itemSpacing == Unit.Empty && (notLast || (displayChildren && !dynamicChildren))) {
458 writer.AddStyleAttribute ("width", "3px");
459 writer.RenderBeginTag (HtmlTextWriterTag.Td);
460 writer.RenderEndTag ();
463 // Bottom separator image
464 string separatorImg = item.SeparatorImageUrl;
465 if (separatorImg.Length == 0) {
467 separatorImg = oc.DynamicBottomSeparatorImageUrl;
469 separatorImg = oc.StaticBottomSeparatorImageUrl;
472 if (separatorImg.Length > 0) {
474 writer.RenderBeginTag (HtmlTextWriterTag.Td);
475 RenderSeparatorImage (owner, writer, separatorImg, false);
477 writer.RenderEndTag (); // TD
481 writer.RenderEndTag (); // TR
483 if (itemSpacing != Unit.Empty)
484 RenderMenuItemSpacing (writer, itemSpacing, isVertical);
488 if (displayChildren && !dynamicChildren) {
490 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
491 writer.RenderBeginTag (HtmlTextWriterTag.Td);
492 writer.AddAttribute ("width", "100%");
493 owner.RenderMenu (writer, item.ChildItems, vertical, false, item.Depth + 1, notLast);
494 if (item.Depth + 2 == oc.StaticDisplayLevels)
495 owner.RenderDynamicMenu (writer, item.ChildItems);
496 writer.RenderEndTag (); // TD
498 writer.RenderEndTag (); // TR
502 public override bool IsDynamicItem (Menu owner, MenuItem item)
505 throw new ArgumentNullException ("owner");
508 throw new ArgumentNullException ("item");
510 return item.Depth + 1 > owner.StaticDisplayLevels;