diff --git a/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js b/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js index 7e73c13763..43313bd4ed 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js @@ -1,8 +1,30 @@ - +/** + * @ngdoc service + * @name umbraco.services.umbracoMenuActions + * + * @requires q + * @requires treeService + * + * @description + * Defines the methods that are called when menu items declare only an action to execute + */ function umbracoMenuActions($q, treeService) { return { - refresh: function(args) { + + /** + * @ngdoc method + * @name umbraco.services.umbracoMenuActions#RefreshNodeMenuItem + * @methodOf umbraco.services.umbracoMenuActions + * @function + * + * @description + * Clears all node children and then gets it's up-to-date children from the server and re-assigns them + * @param {object} args An arguments object + * @param {object} args.treeNode The tree node + * @param {object} args.section The current section + */ + "RefreshNodeMenuItem": function (args) { treeService.loadNodeChildren({ node: args.treeNode, section: args.section }); } }; diff --git a/src/Umbraco.Web/Trees/Menu/ActionMenuItem.cs b/src/Umbraco.Web/Trees/Menu/ActionMenuItem.cs index a0227c2f1f..a2bdffaee2 100644 --- a/src/Umbraco.Web/Trees/Menu/ActionMenuItem.cs +++ b/src/Umbraco.Web/Trees/Menu/ActionMenuItem.cs @@ -10,7 +10,11 @@ namespace Umbraco.Web.Trees.Menu /// These types of menu items are rare but they do exist. Things like refresh node simply execute /// JS and don't launch a dialog. /// - /// Each action menu item describes what angular service that it's method exists in and what the method name is + /// Each action menu item describes what angular service that it's method exists in and what the method name is. + /// + /// An action menu item must describe the angular service name for which it's method exists. It may also define what the + /// method name is that will be called in this service but if one is not specified then we will assume the method name is the + /// same as the Type name of the current action menu class. /// public abstract class ActionMenuItem : MenuItem { @@ -24,7 +28,15 @@ namespace Umbraco.Web.Trees.Menu } //add the current type to the metadata - AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, attribute.MethodName)); + 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 + AdditionalData.Add("jsAction", string.Format("{0}.{1}", attribute.ServiceName, this.GetType().Name)); + } + else + { + 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/ActionMenuItemAttribute.cs b/src/Umbraco.Web/Trees/Menu/ActionMenuItemAttribute.cs index c9efd67f68..9bbe0317fd 100644 --- a/src/Umbraco.Web/Trees/Menu/ActionMenuItemAttribute.cs +++ b/src/Umbraco.Web/Trees/Menu/ActionMenuItemAttribute.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core; namespace Umbraco.Web.Trees.Menu { @@ -8,12 +9,30 @@ namespace Umbraco.Web.Trees.Menu [AttributeUsage(AttributeTargets.Class)] public sealed class ActionMenuItemAttribute : Attribute { + /// + /// This constructor defines both the angular service and method name to use + /// + /// + /// public ActionMenuItemAttribute(string serviceName, string methodName) { + Mandate.ParameterNotNullOrEmpty(serviceName, "serviceName"); + Mandate.ParameterNotNullOrEmpty(methodName, "methodName"); MethodName = methodName; ServiceName = serviceName; } + /// + /// This constructor will assume that the method name equals the type name of the action menu class + /// + /// + public ActionMenuItemAttribute(string serviceName) + { + Mandate.ParameterNotNullOrEmpty(serviceName, "serviceName"); + MethodName = ""; + ServiceName = serviceName; + } + public string MethodName { get; private set; } public string ServiceName { get; private set; } } diff --git a/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs b/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs index d21bc1e05f..a5ca1e3a9e 100644 --- a/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs +++ b/src/Umbraco.Web/Trees/Menu/MenuItemCollection.cs @@ -1,7 +1,9 @@ -using System.Collections; +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 @@ -28,6 +30,9 @@ namespace Umbraco.Web.Trees.Menu internal MenuItem AddMenuItem(IAction action) { var item = new MenuItem(action); + + DetectLegacyActionMenu(action.GetType(), item); + _menuItems.Add(item); return item; } @@ -105,6 +110,8 @@ namespace Umbraco.Web.Trees.Menu } } + 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 @@ -134,6 +141,32 @@ namespace Umbraco.Web.Trees.Menu 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)); + } + } + } + public IEnumerator GetEnumerator() { return _menuItems.GetEnumerator(); diff --git a/src/Umbraco.Web/Trees/Menu/RefreshNodeMenuItem.cs b/src/Umbraco.Web/Trees/Menu/RefreshNodeMenuItem.cs index 672c88951e..c82fbdb588 100644 --- a/src/Umbraco.Web/Trees/Menu/RefreshNodeMenuItem.cs +++ b/src/Umbraco.Web/Trees/Menu/RefreshNodeMenuItem.cs @@ -3,7 +3,7 @@ /// /// Represents the refresh node menu item /// - [ActionMenuItem("umbracoMenuActions", "refresh")] + [ActionMenuItem("umbracoMenuActions")] public sealed class RefreshNodeMenuItem : ActionMenuItem { } diff --git a/src/umbraco.cms/Actions/ActionRefresh.cs b/src/umbraco.cms/Actions/ActionRefresh.cs index f8bbb0a0bf..9aa0a4fe78 100644 --- a/src/umbraco.cms/Actions/ActionRefresh.cs +++ b/src/umbraco.cms/Actions/ActionRefresh.cs @@ -4,17 +4,16 @@ using umbraco.BasePages; namespace umbraco.BusinessLogic.Actions { - /// + /// /// This action is invoked when a node reloads its children /// Concerns only the tree itself and thus you should not handle /// this action from without umbraco. /// + [LegacyActionMenuItem("umbracoMenuActions", "RefreshNodeMenuItem")] public class ActionRefresh : IAction { //create singleton -#pragma warning disable 612,618 - private static readonly ActionRefresh m_instance = new ActionRefresh(); -#pragma warning restore 612,618 + private static readonly ActionRefresh InnerInstance = new ActionRefresh(); /// /// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons. @@ -26,7 +25,7 @@ namespace umbraco.BusinessLogic.Actions public static ActionRefresh Instance { - get { return m_instance; } + get { return InnerInstance; } } #region IAction Members diff --git a/src/umbraco.cms/Actions/LegacyActionMenuItemAttribute.cs b/src/umbraco.cms/Actions/LegacyActionMenuItemAttribute.cs new file mode 100644 index 0000000000..12ad9db580 --- /dev/null +++ b/src/umbraco.cms/Actions/LegacyActionMenuItemAttribute.cs @@ -0,0 +1,43 @@ +using System; +using Umbraco.Core; + +namespace umbraco.BusinessLogic.Actions +{ + /// + /// The attribute to assign to any IAction objects. + /// + /// + /// This is purely used for compatibility reasons for old IActions used in v7 that haven't been upgraded to + /// the new format. + /// + [AttributeUsage(AttributeTargets.Class)] + internal sealed class LegacyActionMenuItemAttribute : Attribute + { + /// + /// This constructor defines both the angular service and method name to use + /// + /// + /// + public LegacyActionMenuItemAttribute(string serviceName, string methodName) + { + Mandate.ParameterNotNullOrEmpty(serviceName, "serviceName"); + Mandate.ParameterNotNullOrEmpty(methodName, "methodName"); + MethodName = methodName; + ServiceName = serviceName; + } + + /// + /// This constructor will assume that the method name equals the type name of the action menu class + /// + /// + public LegacyActionMenuItemAttribute(string serviceName) + { + Mandate.ParameterNotNullOrEmpty(serviceName, "serviceName"); + MethodName = ""; + ServiceName = serviceName; + } + + public string MethodName { get; private set; } + public string ServiceName { get; private set; } + } +} \ No newline at end of file diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index d12afb28dc..ec465eedf7 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -209,6 +209,7 @@ Code +