Files
Umbraco-CMS/src/Umbraco.Web/Models/Trees/MenuItemList.cs

181 lines
6.9 KiB
C#

using System;
using System.Collections.Generic;
using Umbraco.Core;
using umbraco.BusinessLogic.Actions;
using umbraco.interfaces;
namespace Umbraco.Web.Models.Trees
{
/// <summary>
/// A custom menu list
/// </summary>
/// <remarks>
/// NOTE: We need a sub collection to the MenuItemCollection object due to how json serialization works.
/// </remarks>
public class MenuItemList : List<MenuItem>
{
public MenuItemList()
{
}
public MenuItemList(IEnumerable<MenuItem> items)
: base(items)
{
}
/// <summary>
/// Adds a menu item
/// </summary>
/// <param name="action"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
internal MenuItem Add(IAction action, string name)
{
var item = new MenuItem(action);
DetectLegacyActionMenu(action.GetType(), item);
Add(item);
return item;
}
/// <summary>
/// Adds a menu item
/// </summary>
/// <typeparam name="TMenuItem"></typeparam>
/// <typeparam name="TAction"></typeparam>
/// <param name="hasSeparator"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="additionalData"></param>
/// <returns></returns>
public TMenuItem Add<TMenuItem, TAction>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
where TAction : IAction
where TMenuItem : MenuItem, new()
{
var item = CreateMenuItem<TAction>(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;
}
/// <summary>
/// Adds a menu item
/// </summary>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <typeparam name="T"></typeparam>
public MenuItem Add<T>(string name)
where T : IAction
{
return Add<T>(name, false, null);
}
/// <summary>
/// Adds a menu item with a key value pair which is merged to the AdditionalData bag
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="hasSeparator"></param>
public MenuItem Add<T>(string name, string key, string value, bool hasSeparator = false)
where T : IAction
{
return Add<T>(name, hasSeparator, new Dictionary<string, object> { { key, value } });
}
/// <summary>
/// Adds a menu item with a dictionary which is merged to the AdditionalData bag
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hasSeparator"></param>
/// /// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="additionalData"></param>
public MenuItem Add<T>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
where T : IAction
{
var item = CreateMenuItem<T>(name, hasSeparator, additionalData);
if (item != null)
{
Add(item);
return item;
}
return null;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hasSeparator"></param>
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
/// <param name="additionalData"></param>
/// <returns></returns>
internal MenuItem CreateMenuItem<T>(string name, bool hasSeparator = false, IDictionary<string, object> additionalData = null)
where T : IAction
{
var item = ActionsResolver.Current.GetAction<T>();
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;
}
/// <summary>
/// Checks if the IAction type passed in is attributed with LegacyActionMenuItemAttribute and if so
/// ensures that the correct action metadata is added.
/// </summary>
/// <param name="actionType"></param>
/// <param name="menuItem"></param>
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<LegacyActionMenuItemAttribute>(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));
}
}
}
}
}