2 // System.Web.UI.WebControls.Menu.cs
5 // Lluis Sanchez Gual (lluis@novell.com)
7 // (C) 2004 Novell, Inc (http://www.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.
34 using System.Collections;
36 using System.ComponentModel;
38 using System.Web.Handlers;
39 using System.Collections.Specialized;
42 namespace System.Web.UI.WebControls
44 public class Menu : HierarchicalDataBoundControl, IPostBackEventHandler, INamingContainer
46 MenuItemCollection items;
47 MenuItemBindingCollection dataBindings;
48 MenuItem selectedItem;
51 [PersistenceMode (PersistenceMode.InnerProperty)]
52 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
53 [Editor ("System.Web.UI.Design.MenuItemBindingsEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
54 public virtual MenuItemBindingCollection DataBindings {
56 if (dataBindings == null) {
57 dataBindings = new MenuItemBindingCollection ();
58 if (IsTrackingViewState)
59 ((IStateManager)dataBindings).TrackViewState();
66 public virtual int DisappearAfter {
68 object o = ViewState ["DisappearAfter"];
69 if (o != null) return (int)o;
73 ViewState["DisappearAfter"] = value;
79 [WebCategory ("Appearance")]
80 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
81 public virtual string DynamicBottomSeparatorImageUrl {
83 object o = ViewState ["dbsiu"];
84 if (o != null) return (string)o;
88 ViewState["dbsiu"] = value;
92 [DefaultValue (Orientation.Vertical)]
93 public virtual Orientation Orientation {
95 object o = ViewState ["Orientation"];
96 if (o != null) return (Orientation) o;
97 return Orientation.Vertical;
100 ViewState["Orientation"] = value;
105 public virtual int StaticDisplayLevels {
107 object o = ViewState ["StaticDisplayLevels"];
108 if (o != null) return (int)o;
112 if (value < 1) throw new ArgumentOutOfRangeException ();
113 ViewState["StaticDisplayLevels"] = value;
117 [DefaultValue ("16px")]
118 public Unit StaticSubMenuIndent {
120 object o = ViewState ["StaticSubMenuIndent"];
121 if (o != null) return (Unit)o;
122 return new Unit (16);
125 ViewState["StaticSubMenuIndent"] = value;
130 public virtual int MaximumDynamicDisplayLevels {
132 object o = ViewState ["MaximumDynamicDisplayLevels"];
133 if (o != null) return (int)o;
137 if (value < 0) throw new ArgumentOutOfRangeException ();
138 ViewState["MaximumDynamicDisplayLevels"] = value;
142 /* [DefaultValue (true)]
143 public virtual bool DynamicEnableDefaultPopOutImage {
145 object o = ViewState ["dedpoi"];
146 if (o != null) return (bool)o;
150 ViewState["dedpoi"] = value;
154 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
155 [PersistenceMode (PersistenceMode.InnerProperty)]
156 [Editor ("System.Web.UI.Design.MenuItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
157 public virtual MenuItemCollection Items {
160 items = new MenuItemCollection (this);
161 if (IsTrackingViewState)
162 ((IStateManager)items).TrackViewState();
169 public virtual char PathSeparator {
171 object o = ViewState ["PathSeparator"];
172 if(o != null) return (char)o;
176 ViewState ["PathSeparator"] = value;
181 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
182 public MenuItem SelectedItem {
183 get { return selectedItem; }
186 internal void SetSelectedItem (MenuItem item)
188 if (selectedItem == item) return;
189 if (selectedItem != null)
190 selectedItem.SelectedFlag = false;
192 selectedItem.SelectedFlag = true;
193 // OnSelectedItemChanged (new MenuItemEventArgs (selectedItem));
196 public MenuItem FindItem (string valuePath)
198 if (valuePath == null) throw new ArgumentNullException ("valuePath");
199 string[] path = valuePath.Split (PathSeparator);
201 MenuItemCollection col = Items;
202 bool foundBranch = true;
203 while (col.Count > 0 && foundBranch) {
205 foreach (MenuItem item in col) {
206 if (item.Value == path [n]) {
207 if (++n == path.Length) return item;
208 col = item.ChildItems;
217 string GetBindingKey (string dataMember, int depth)
219 return dataMember + " " + depth;
222 internal MenuItemBinding FindBindingForItem (string type, int depth)
224 if (bindings == null) return null;
226 MenuItemBinding bin = (MenuItemBinding) bindings [GetBindingKey (type, depth)];
227 if (bin != null) return bin;
229 bin = (MenuItemBinding) bindings [GetBindingKey (type, -1)];
230 if (bin != null) return bin;
232 bin = (MenuItemBinding) bindings [GetBindingKey ("", depth)];
233 if (bin != null) return bin;
235 bin = (MenuItemBinding) bindings [GetBindingKey ("", -1)];
239 protected internal override void PerformDataBinding ()
241 base.PerformDataBinding ();
242 HierarchicalDataSourceView data = GetData ("");
243 IHierarchicalEnumerable e = data.Select ();
244 foreach (object obj in e) {
245 IHierarchyData hdata = e.GetHierarchyData (obj);
246 MenuItem item = new MenuItem ();
252 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
256 protected override void TrackViewState()
260 base.TrackViewState();
261 if (dataBindings != null) {
262 ((IStateManager)dataBindings).TrackViewState ();
265 ((IStateManager)items).TrackViewState();;
269 protected override object SaveViewState()
271 object[] states = new object [3];
272 states[0] = base.SaveViewState();
273 states[1] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
274 states[2] = (items == null ? null : ((IStateManager)items).SaveViewState());
276 for (int i = states.Length - 1; i >= 0; i--) {
277 if (states [i] != null)
284 protected override void LoadViewState (object savedState)
286 if (savedState == null)
289 object [] states = (object []) savedState;
290 base.LoadViewState (states[0]);
292 if (states[1] != null)
293 ((IStateManager)dataBindings).LoadViewState(states[8]);
294 if (states[2] != null)
295 ((IStateManager)Items).LoadViewState(states[9]);
298 protected override void OnPreRender (EventArgs e)
300 base.OnPreRender (e);
302 if (!Page.ClientScript.IsClientScriptIncludeRegistered (typeof(Menu), "Menu.js")) {
303 string url = Page.GetWebResourceUrl (typeof(Menu), "Menu.js");
304 Page.ClientScript.RegisterClientScriptInclude (typeof(Menu), "Menu.js", url);
306 string cmenu = ClientID + "_data";
307 string script = string.Format ("var {0} = new Object ();\n", cmenu);
308 script += string.Format ("{0}.disappearAfter = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (DisappearAfter));
309 script += string.Format ("{0}.vertical = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (Orientation == Orientation.Vertical));
311 Page.ClientScript.RegisterStartupScript (typeof(Menu), "", script, true);
314 if (dataBindings != null && dataBindings.Count > 0) {
315 bindings = new Hashtable ();
316 foreach (TreeNodeBinding bin in dataBindings) {
317 string key = GetBindingKey (bin.DataMember, bin.Depth);
318 bindings [key] = bin;
325 protected override void RenderContents (HtmlTextWriter writer)
327 ArrayList dynamicMenus = new ArrayList ();
329 if (Orientation == Orientation.Horizontal) {
330 writer.AddAttribute ("cellpadding", "0");
331 writer.AddAttribute ("cellspacing", "0");
332 writer.AddStyleAttribute ("border-width", "0");
333 writer.RenderBeginTag (HtmlTextWriterTag.Table);
334 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
337 foreach (MenuItem item in Items) {
338 RenderMenuItem (writer, item, dynamicMenus);
341 if (Orientation == Orientation.Horizontal) {
342 writer.RenderEndTag (); // TR
343 writer.RenderEndTag (); // TABLE
346 for (int n=0; n<dynamicMenus.Count; n++) {
347 MenuItem item = (MenuItem) dynamicMenus [n];
348 writer.AddStyleAttribute ("display", "none");
349 writer.AddStyleAttribute ("visibility", "hidden");
350 writer.AddStyleAttribute ("position", "absolute");
351 writer.AddStyleAttribute ("left", "0px");
352 writer.AddStyleAttribute ("top", "0px");
353 writer.AddAttribute ("id", GetItemClientId (item, "s"));
354 writer.RenderBeginTag (HtmlTextWriterTag.Div);
356 foreach (MenuItem mi in item.ChildItems) {
357 RenderMenuItem (writer, mi, dynamicMenus);
360 writer.RenderEndTag (); // DIV
364 void RenderMenuItem (HtmlTextWriter writer, MenuItem item, ArrayList dynamicMenus)
366 bool displayChildren = (item.Depth + 1 < StaticDisplayLevels + MaximumDynamicDisplayLevels);
367 bool dynamicChildren = displayChildren && (item.Depth + 1 >= StaticDisplayLevels) && item.ChildItems.Count > 0;
368 bool isDynamicItem = item.Depth + 1 > StaticDisplayLevels;
370 if (Orientation == Orientation.Vertical) {
371 writer.AddAttribute ("cellpadding", "0");
372 writer.AddAttribute ("cellspacing", "0");
373 writer.AddStyleAttribute ("border-width", "0");
374 writer.RenderBeginTag (HtmlTextWriterTag.Table);
375 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
378 if (item.Depth > 0 && !isDynamicItem) {
379 for (int n=0; n<item.Depth; n++) {
380 writer.RenderBeginTag (HtmlTextWriterTag.Td);
381 writer.AddStyleAttribute ("width", StaticSubMenuIndent.ToString ());
382 writer.RenderBeginTag (HtmlTextWriterTag.Div);
383 writer.RenderEndTag (); // DIV
384 writer.RenderEndTag (); // TD
388 writer.RenderBeginTag (HtmlTextWriterTag.Td);
390 if (item.NavigateUrl != "") {
391 writer.AddAttribute ("href", item.NavigateUrl);
392 if (item.Target != null)
393 writer.AddAttribute ("target", item.Target);
394 writer.AddStyleAttribute ("text-decoration", "none");
397 writer.AddAttribute ("href", GetClientEvent (item, "sel"));
398 writer.AddStyleAttribute ("text-decoration", "none");
401 string parentId = item.Parent != null ? "'" + item.Parent.Path + "'" : "null";
402 if (dynamicChildren) {
403 writer.AddAttribute ("onmouseover", "javascript:Menu_OverItem ('" + ClientID + "', '" + item.Path + "', " + parentId + ")");
404 writer.AddAttribute ("onmouseout", "javascript:Menu_OutItem ('" + ClientID + "', '" + item.Path + "')");
405 } else if (isDynamicItem) {
406 writer.AddAttribute ("onmouseover", "javascript:Menu_OverLeafItem ('" + ClientID + "', " + parentId + ")");
407 writer.AddAttribute ("onmouseout", "javascript:Menu_OutItem ('" + ClientID + "', " + parentId + ")");
410 writer.AddAttribute ("id", GetItemClientId (item, "i"));
411 writer.RenderBeginTag (HtmlTextWriterTag.A);
412 writer.Write (item.Text);
413 writer.RenderEndTag (); // A
415 writer.RenderEndTag (); // TD
417 if (Orientation == Orientation.Vertical) {
418 writer.RenderEndTag (); // TR
419 writer.RenderEndTag (); // TABLE
422 if (displayChildren) {
423 if (dynamicChildren) {
424 dynamicMenus.Add (item);
426 foreach (MenuItem mi in item.ChildItems) {
427 RenderMenuItem (writer, mi, dynamicMenus);
433 string GetItemClientId (MenuItem item, string sufix)
435 return ClientID + "_" + item.Path + sufix;
438 string GetClientEvent (MenuItem item, string ev)
440 return Page.GetPostBackClientHyperlink (this, ev + "|" + item.Path);