From 936be3934bf3cdef9e056694a28783ddb19e76b8 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 3 Oct 2013 15:05:48 +1000 Subject: [PATCH] Updated MenuItemCollection with MenuItemList for full featured List access to the items. Added the MenuRendering event to TreeController, updated the tree controller events to be TypedEventHandler's though developers will need to cast the TreeController to the type they are expecting - still better than 'object'. --- .../MyPackage/Trees/LegacyTestTree.cs | 2 +- .../Trees/ContentTreeController.cs | 42 ++-- .../Trees/ContentTreeControllerBase.cs | 8 +- .../Trees/DataTypeTreeController.cs | 8 +- src/Umbraco.Web/Trees/LegacyTreeController.cs | 4 +- .../Trees/LegacyTreeDataConverter.cs | 8 +- src/Umbraco.Web/Trees/MediaTreeController.cs | 16 +- src/Umbraco.Web/Trees/MemberTreeController.cs | 8 +- .../Trees/Menu/MenuItemCollection.cs | 198 ++---------------- src/Umbraco.Web/Trees/Menu/MenuItemList.cs | 181 ++++++++++++++++ .../Trees/MenuRenderingEventArgs.cs | 25 +++ src/Umbraco.Web/Trees/TreeController.cs | 37 +++- .../Trees/TreeNodeRenderingEventArgs.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 + 14 files changed, 303 insertions(+), 238 deletions(-) create mode 100644 src/Umbraco.Web/Trees/Menu/MenuItemList.cs create mode 100644 src/Umbraco.Web/Trees/MenuRenderingEventArgs.cs diff --git a/src/Umbraco.Web.UI/App_Plugins/MyPackage/Trees/LegacyTestTree.cs b/src/Umbraco.Web.UI/App_Plugins/MyPackage/Trees/LegacyTestTree.cs index 1dfaf4da44..4e46cae0e2 100644 --- a/src/Umbraco.Web.UI/App_Plugins/MyPackage/Trees/LegacyTestTree.cs +++ b/src/Umbraco.Web.UI/App_Plugins/MyPackage/Trees/LegacyTestTree.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.UI.App_Plugins.MyPackage.Trees protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) { var menu = new MenuItemCollection(); - menu.AddMenuItem(new MenuItem("create", "Create")); + menu.Add(new MenuItem("create", "Create")); return menu; } } diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 1d66121de2..0e7aef2a2d 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -107,20 +107,20 @@ namespace Umbraco.Web.Trees .Select(x => new MenuItem(x)); //these two are the standard items - menu.AddMenuItem(ui.Text("actions", ActionNew.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(null, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionNew.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(null, "content", "content"); //filter the standard items FilterUserAllowedMenuItems(menu, nodeActions); - if (menu.MenuItems.Any()) + if (menu.Items.Any()) { - menu.MenuItems.Last().SeperatorBefore = true; + menu.Items.Last().SeperatorBefore = true; } // add default actions for *all* users - menu.AddMenuItem(ui.Text("actions", ActionRePublish.Instance.Alias)).ConvertLegacyMenuItem(null, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionRePublish.Instance.Alias)).ConvertLegacyMenuItem(null, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } @@ -162,26 +162,26 @@ namespace Umbraco.Web.Trees protected MenuItemCollection GetAllNodeMenuItems(IUmbracoEntity item) { var menu = new MenuItemCollection(); - menu.AddMenuItem(ui.Text("actions", ActionNew.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionNew.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionDelete.Instance.Alias)); //need to ensure some of these are converted to the legacy system - until we upgrade them all to be angularized. - menu.AddMenuItem(ui.Text("actions", ActionMove.Instance.Alias), true); - menu.AddMenuItem(ui.Text("actions", ActionCopy.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionMove.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionCopy.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionRollback.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionPublish.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionToPublish.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionAssignDomain.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionRights.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionProtect.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionUnPublish.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionNotify.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionSendToTranslate.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionRollback.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionPublish.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionToPublish.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionAssignDomain.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionRights.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionProtect.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionUnPublish.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionNotify.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); + menu.Items.Add(ui.Text("actions", ActionSendToTranslate.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index ff4a6f2fd1..c97c586e10 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -96,8 +96,8 @@ namespace Umbraco.Web.Trees if (RecycleBinId.ToInvariantString() == id) { var menu = new MenuItemCollection(); - menu.AddMenuItem(ui.Text("actions", ActionEmptyTranscan.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionEmptyTranscan.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } return PerformGetMenuForNode(id, queryStrings); @@ -113,7 +113,7 @@ namespace Umbraco.Web.Trees { var userAllowedActions = userAllowedMenuItems.Where(x => x.Action != null).Select(x => x.Action).ToArray(); - var notAllowed = menuWithAllItems.MenuItems.Where( + var notAllowed = menuWithAllItems.Items.Where( a => (a.Action != null && a.Action.CanBePermissionAssigned && (a.Action.CanBePermissionAssigned == false || userAllowedActions.Contains(a.Action) == false))) @@ -122,7 +122,7 @@ namespace Umbraco.Web.Trees //remove the ones that aren't allowed. foreach (var m in notAllowed) { - menuWithAllItems.RemoveMenuItem(m); + menuWithAllItems.Items.Remove(m); } } diff --git a/src/Umbraco.Web/Trees/DataTypeTreeController.cs b/src/Umbraco.Web/Trees/DataTypeTreeController.cs index a5203da563..c627de0bc4 100644 --- a/src/Umbraco.Web/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/DataTypeTreeController.cs @@ -47,13 +47,13 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { // root actions - menu.AddMenuItem(ui.Text("actions", ActionNew.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionNew.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } - + //only have delete for each node - menu.AddMenuItem(ui.Text("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionDelete.Instance.Alias)); return menu; } } diff --git a/src/Umbraco.Web/Trees/LegacyTreeController.cs b/src/Umbraco.Web/Trees/LegacyTreeController.cs index 4fa7d35edf..cdb6958570 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeController.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeController.cs @@ -75,7 +75,7 @@ namespace Umbraco.Web.Trees throw new ApplicationException(msg); } - foreach (var menuItem in attempt.Result.MenuItems) + foreach (var menuItem in attempt.Result.Items) { menuItem.Name = global::umbraco.ui.Text("actions", menuItem.Alias); } @@ -90,7 +90,7 @@ namespace Umbraco.Web.Trees LogHelper.Error(msg, attempt.Exception); throw new ApplicationException(msg); } - foreach (var menuItem in attempt.Result.MenuItems) + foreach (var menuItem in attempt.Result.Items) { menuItem.Name = global::umbraco.ui.Text("actions", menuItem.Alias); } diff --git a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs index 290c722cd0..f0400712ea 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs @@ -143,11 +143,11 @@ namespace Umbraco.Web.Trees if (t is ContextMenuSeperator && numAdded > 0) { //store the index for which the seperator should be placed - seperators.Add(collection.MenuItems.Count()); + seperators.Add(collection.Items.Count()); } else { - var menuItem = collection.AddMenuItem(t, ui.Text("actions", t.Alias)); + var menuItem = collection.Items.Add(t, ui.Text("actions", t.Alias)); var currentAction = t; @@ -164,12 +164,12 @@ namespace Umbraco.Web.Trees numAdded++; } } - var length = collection.MenuItems.Count(); + var length = collection.Items.Count(); foreach (var s in seperators) { if (length >= s) { - collection.MenuItems.ElementAt(s).SeperatorBefore = true; + collection.Items.ElementAt(s).SeperatorBefore = true; } } diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs index 22fabe5da8..247337ff3d 100644 --- a/src/Umbraco.Web/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web/Trees/MediaTreeController.cs @@ -77,9 +77,9 @@ namespace Umbraco.Web.Trees } // root actions - menu.AddMenuItem(ui.Text("actions", ActionNew.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(null, "media", "media"); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionNew.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionSort.Instance.Alias), true).ConvertLegacyMenuItem(null, "media", "media"); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } @@ -94,11 +94,11 @@ namespace Umbraco.Web.Trees throw new HttpResponseException(HttpStatusCode.NotFound); } //return a normal node menu: - menu.AddMenuItem(ui.Text("actions", ActionNew.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionMove.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionDelete.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionSort.Instance.Alias)).ConvertLegacyMenuItem(null, "media", "media"); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionNew.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionMove.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionSort.Instance.Alias)).ConvertLegacyMenuItem(null, "media", "media"); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } diff --git a/src/Umbraco.Web/Trees/MemberTreeController.cs b/src/Umbraco.Web/Trees/MemberTreeController.cs index 8350662265..d4920cd9c4 100644 --- a/src/Umbraco.Web/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web/Trees/MemberTreeController.cs @@ -80,13 +80,13 @@ namespace Umbraco.Web.Trees menu.DefaultMenuAlias = ActionNew.Instance.Alias; // root actions - menu.AddMenuItem(ui.Text("actions", ActionNew.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionNew.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } - menu.AddMenuItem(ui.Text("actions", ActionDelete.Instance.Alias)); - menu.AddMenuItem(ui.Text("actions", ActionRefresh.Instance.Alias), true); + menu.Items.Add(ui.Text("actions", ActionDelete.Instance.Alias)); + menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); return menu; } } diff --git a/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs b/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs index bd71a8d595..ea57fb7a07 100644 --- a/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs +++ b/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs @@ -1,28 +1,24 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization; -using Umbraco.Core; -using umbraco.BusinessLogic.Actions; -using umbraco.interfaces; namespace Umbraco.Web.Trees.Menu { - + /// + /// A menu item collection for a given tree node + /// [DataContract(Name = "menuItems", Namespace = "")] - public class MenuItemCollection + public class MenuItemCollection { - //private readonly string _packageFolderName; - private readonly List _menuItems; - + private readonly MenuItemList _menuItems = new MenuItemList(); + public MenuItemCollection() - { - _menuItems = new List(); + { } public MenuItemCollection(IEnumerable items) { - _menuItems = new List(items); + _menuItems = new MenuItemList(items); } /// @@ -34,184 +30,16 @@ namespace Umbraco.Web.Trees.Menu /// /// The list of menu items /// + /// + /// We require this so the json serialization works correctly + /// [DataMember(Name = "menuItems")] - public IEnumerable MenuItems + public MenuItemList Items { get { return _menuItems; } } - /// - /// Adds a menu item - /// - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - internal MenuItem AddMenuItem(IAction action, string name) - { - var item = new MenuItem(action); - - DetectLegacyActionMenu(action.GetType(), item); - - _menuItems.Add(item); - return item; - } - - /// - /// Removes a menu item - /// - /// - public void RemoveMenuItem(MenuItem item) - { - _menuItems.Remove(item); - } - - /// - /// Adds a menu item - /// - public void AddMenuItem(MenuItem item) - { - _menuItems.Add(item); - } - /// - /// Adds a menu item - /// - /// - /// - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - /// - public TMenuItem AddMenuItem(string name, bool hasSeparator = false, IDictionary additionalData = null) - where TAction : IAction - where TMenuItem : MenuItem, new() - { - var item = CreateMenuItem(name, hasSeparator, additionalData); - if (item == null) return null; - - var customMenuItem = new TMenuItem - { - Name = item.Alias, - Alias = item.Alias, - SeperatorBefore = hasSeparator, - Icon = item.Icon, - Action = item.Action - }; - - _menuItems.Add(customMenuItem); - - return customMenuItem; - } - - /// - /// Adds a menu item - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - public MenuItem AddMenuItem(string name) - where T : IAction - { - return AddMenuItem(name, false, null); - } - - /// - /// Adds a menu item with a key value pair which is merged to the AdditionalData bag - /// - /// - /// - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - public MenuItem AddMenuItem(string name, string key, string value, bool hasSeparator = false) - where T : IAction - { - return AddMenuItem(name, hasSeparator, new Dictionary { { key, value } }); - } - - /// - /// Adds a menu item with a dictionary which is merged to the AdditionalData bag - /// - /// - /// - /// /// The text to display for the menu item, will default to the IAction alias if not specified - /// - public MenuItem AddMenuItem(string name, bool hasSeparator = false, IDictionary additionalData = null) - where T : IAction - { - var item = CreateMenuItem(name, hasSeparator, additionalData); - if (item != null) - { - _menuItems.Add(item); - return item; - } - return null; - } - - /// - /// - /// - /// - /// - /// The text to display for the menu item, will default to the IAction alias if not specified - /// - /// - internal MenuItem CreateMenuItem(string name, bool hasSeparator = false, IDictionary additionalData = null) - where T : IAction - { - var item = ActionsResolver.Current.GetAction(); - if (item != null) - { - var menuItem = new MenuItem(item, name) - { - SeperatorBefore = hasSeparator - }; - - if (additionalData != null) - { - foreach (var i in additionalData) - { - menuItem.AdditionalData[i.Key] = i.Value; - } - } - - DetectLegacyActionMenu(typeof(T), menuItem); - - //TODO: Once we implement 'real' menu items, not just IActions we can implement this since - // people may need to pass specific data to their menu items - - ////validate the data in the meta data bag - //item.ValidateRequiredData(AdditionalData); - - return menuItem; - } - return null; - } - - /// - /// Checks if the IAction type passed in is attributed with LegacyActionMenuItemAttribute and if so - /// ensures that the correct action metadata is added. - /// - /// - /// - private void DetectLegacyActionMenu(Type actionType, MenuItem menuItem) - { - //This checks for legacy IActions that have the LegacyActionMenuItemAttribute which is a legacy hack - // to make old IAction actions work in v7 by mapping to the JS used by the new menu items - var attribute = actionType.GetCustomAttribute(false); - if (attribute != null) - { - //add the current type to the metadata - if (attribute.MethodName.IsNullOrWhiteSpace()) - { - //if no method name is supplied we will assume that the menu action is the type name of the current menu class - menuItem.AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, this.GetType().Name)); - } - else - { - menuItem.AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, attribute.MethodName)); - } - } - } - } } \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/Menu/MenuItemList.cs b/src/Umbraco.Web/Trees/Menu/MenuItemList.cs new file mode 100644 index 0000000000..60c32b02e0 --- /dev/null +++ b/src/Umbraco.Web/Trees/Menu/MenuItemList.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core; +using umbraco.BusinessLogic.Actions; +using umbraco.interfaces; + +namespace Umbraco.Web.Trees.Menu +{ + /// + /// A custom menu list + /// + /// + /// NOTE: We need a sub collection to the MenuItemCollection object due to how json serialization works. + /// + public class MenuItemList : List + { + public MenuItemList() + { + } + + public MenuItemList(IEnumerable items) + : base(items) + { + } + + /// + /// Adds a menu item + /// + /// + /// The text to display for the menu item, will default to the IAction alias if not specified + internal MenuItem Add(IAction action, string name) + { + var item = new MenuItem(action); + + DetectLegacyActionMenu(action.GetType(), item); + + Add(item); + return item; + } + + /// + /// Adds a menu item + /// + /// + /// + /// + /// The text to display for the menu item, will default to the IAction alias if not specified + /// + /// + public TMenuItem Add(string name, bool hasSeparator = false, IDictionary additionalData = null) + where TAction : IAction + where TMenuItem : MenuItem, new() + { + var item = CreateMenuItem(name, hasSeparator, additionalData); + if (item == null) return null; + + var customMenuItem = new TMenuItem + { + Name = item.Alias, + Alias = item.Alias, + SeperatorBefore = hasSeparator, + Icon = item.Icon, + Action = item.Action + }; + + Add(customMenuItem); + + return customMenuItem; + } + + /// + /// Adds a menu item + /// + /// The text to display for the menu item, will default to the IAction alias if not specified + /// + public MenuItem Add(string name) + where T : IAction + { + return Add(name, false, null); + } + + /// + /// Adds a menu item with a key value pair which is merged to the AdditionalData bag + /// + /// + /// + /// + /// The text to display for the menu item, will default to the IAction alias if not specified + /// + public MenuItem Add(string name, string key, string value, bool hasSeparator = false) + where T : IAction + { + return Add(name, hasSeparator, new Dictionary { { key, value } }); + } + + /// + /// Adds a menu item with a dictionary which is merged to the AdditionalData bag + /// + /// + /// + /// /// The text to display for the menu item, will default to the IAction alias if not specified + /// + public MenuItem Add(string name, bool hasSeparator = false, IDictionary additionalData = null) + where T : IAction + { + var item = CreateMenuItem(name, hasSeparator, additionalData); + if (item != null) + { + Add(item); + return item; + } + return null; + } + + /// + /// + /// + /// + /// + /// The text to display for the menu item, will default to the IAction alias if not specified + /// + /// + internal MenuItem CreateMenuItem(string name, bool hasSeparator = false, IDictionary additionalData = null) + where T : IAction + { + var item = ActionsResolver.Current.GetAction(); + if (item != null) + { + var menuItem = new MenuItem(item, name) + { + SeperatorBefore = hasSeparator + }; + + if (additionalData != null) + { + foreach (var i in additionalData) + { + menuItem.AdditionalData[i.Key] = i.Value; + } + } + + DetectLegacyActionMenu(typeof(T), menuItem); + + //TODO: Once we implement 'real' menu items, not just IActions we can implement this since + // people may need to pass specific data to their menu items + + ////validate the data in the meta data bag + //item.ValidateRequiredData(AdditionalData); + + return menuItem; + } + return null; + } + + /// + /// Checks if the IAction type passed in is attributed with LegacyActionMenuItemAttribute and if so + /// ensures that the correct action metadata is added. + /// + /// + /// + private void DetectLegacyActionMenu(Type actionType, MenuItem menuItem) + { + //This checks for legacy IActions that have the LegacyActionMenuItemAttribute which is a legacy hack + // to make old IAction actions work in v7 by mapping to the JS used by the new menu items + var attribute = actionType.GetCustomAttribute(false); + if (attribute != null) + { + //add the current type to the metadata + if (attribute.MethodName.IsNullOrWhiteSpace()) + { + //if no method name is supplied we will assume that the menu action is the type name of the current menu class + menuItem.AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, this.GetType().Name)); + } + else + { + menuItem.AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, attribute.MethodName)); + } + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/MenuRenderingEventArgs.cs b/src/Umbraco.Web/Trees/MenuRenderingEventArgs.cs new file mode 100644 index 0000000000..72e203f2e0 --- /dev/null +++ b/src/Umbraco.Web/Trees/MenuRenderingEventArgs.cs @@ -0,0 +1,25 @@ +using System.Net.Http.Formatting; +using Umbraco.Web.Trees.Menu; + +namespace Umbraco.Web.Trees +{ + public class MenuRenderingEventArgs : TreeRenderingEventArgs + { + /// + /// The tree node id that the menu is rendering for + /// + public string NodeId { get; private set; } + + /// + /// The menu being rendered + /// + public MenuItemCollection Menu { get; private set; } + + public MenuRenderingEventArgs(string nodeId, MenuItemCollection menu, FormDataCollection queryStrings) + : base(queryStrings) + { + NodeId = nodeId; + Menu = menu; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/TreeController.cs b/src/Umbraco.Web/Trees/TreeController.cs index c624d75656..374e251763 100644 --- a/src/Umbraco.Web/Trees/TreeController.cs +++ b/src/Umbraco.Web/Trees/TreeController.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Net.Http.Formatting; using Umbraco.Core; +using Umbraco.Core.Events; using Umbraco.Web.Mvc; using Umbraco.Web.Trees.Menu; using Umbraco.Web.WebApi; @@ -164,7 +165,10 @@ namespace Umbraco.Web.Trees public MenuItemCollection GetMenu(string id, FormDataCollection queryStrings) { if (queryStrings == null) queryStrings = new FormDataCollection(""); - return GetMenuForNode(id, queryStrings); + var menu = GetMenuForNode(id, queryStrings); + //raise the event + OnMenuRendering(this, new MenuRenderingEventArgs(id, menu, queryStrings)); + return menu; } /// @@ -304,7 +308,14 @@ namespace Umbraco.Web.Trees #endregion #region Events - public static event EventHandler TreeNodesRendering; + + /// + /// An event that allows developers to modify the tree node collection that is being rendered + /// + /// + /// Developers can add/remove/replace/insert/update/etc... any of the tree items in the collection. + /// + public static event TypedEventHandler TreeNodesRendering; private static void OnTreeNodesRendering(TreeController instance, TreeNodesRenderingEventArgs e) { @@ -312,13 +323,31 @@ namespace Umbraco.Web.Trees if (handler != null) handler(instance, e); } - public static event EventHandler RootNodeRendering; + /// + /// An event that allows developer to modify the root tree node that is being rendered + /// + public static event TypedEventHandler RootNodeRendering; private static void OnRootNodeRendering(TreeController instance, TreeNodeRenderingEventArgs e) { var handler = RootNodeRendering; if (handler != null) handler(instance, e); - } + } + + /// + /// An event that allows developers to modify the meun that is being rendered + /// + /// + /// Developers can add/remove/replace/insert/update/etc... any of the tree items in the collection. + /// + public static event TypedEventHandler MenuRendering; + + private static void OnMenuRendering(TreeController instance, MenuRenderingEventArgs e) + { + var handler = MenuRendering; + if (handler != null) handler(instance, e); + } + #endregion } diff --git a/src/Umbraco.Web/Trees/TreeNodeRenderingEventArgs.cs b/src/Umbraco.Web/Trees/TreeNodeRenderingEventArgs.cs index 67af3959dc..883579a964 100644 --- a/src/Umbraco.Web/Trees/TreeNodeRenderingEventArgs.cs +++ b/src/Umbraco.Web/Trees/TreeNodeRenderingEventArgs.cs @@ -6,7 +6,7 @@ namespace Umbraco.Web.Trees { public TreeNode Node { get; private set; } - public TreeNodeRenderingEventArgs(TreeNode node, FormDataCollection queryStrings) + public TreeNodeRenderingEventArgs(TreeNode node, FormDataCollection queryStrings) : base(queryStrings) { Node = node; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c11fa14d2c..c6d7fec225 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -372,7 +372,9 @@ + + ASPXCodeBehind