using System; 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 { [DataContract(Name = "menuItems", Namespace = "")] public class MenuItemCollection { //private readonly string _packageFolderName; private readonly List _menuItems; public MenuItemCollection() { _menuItems = new List(); } public MenuItemCollection(IEnumerable items) { _menuItems = new List(items); } /// /// Sets the default menu item alias to be shown when the menu is launched - this is optional and if not set then the menu will just be shown normally. /// [DataMember(Name = "defaultAlias")] public string DefaultMenuAlias { get; set; } /// /// The list of menu items /// [DataMember(Name = "menuItems")] public IEnumerable MenuItems { 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)); } } } } }