diff --git a/src/Umbraco.Core/Collections/ObservableDictionary.cs b/src/Umbraco.Core/Collections/ObservableDictionary.cs index 6518533476..40269aa4eb 100644 --- a/src/Umbraco.Core/Collections/ObservableDictionary.cs +++ b/src/Umbraco.Core/Collections/ObservableDictionary.cs @@ -125,6 +125,18 @@ namespace Umbraco.Core.Collections } + public void ReplaceAll(IEnumerable values) + { + if (values == null) throw new ArgumentNullException(nameof(values)); + + Clear(); + + foreach (var value in values) + { + Add(value); + } + } + public bool Remove(TKey key) { if (!Indecies.ContainsKey(key)) return false; diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js index dde887776e..a5d960a9ec 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/macro.resource.js @@ -20,14 +20,14 @@ function macroResource($q, $http, umbRequestHelper) { * @param {int} macroId The macro id to get parameters for * */ - getMacroParameters: function (macroId) { + getMacroParameters: function(macroId) { return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "macroApiBaseUrl", - "GetMacroParameters", - [{ macroId: macroId }])), - 'Failed to retrieve macro parameters for macro with id ' + macroId); + $http.get( + umbRequestHelper.getApiUrl( + "macroRenderingApiBaseUrl", + "GetMacroParameters", + [{ macroId: macroId }])), + 'Failed to retrieve macro parameters for macro with id ' + macroId); }, /** @@ -43,13 +43,14 @@ function macroResource($q, $http, umbRequestHelper) { * @param {Array} macroParamDictionary A dictionary of macro parameters * */ - getMacroResultAsHtmlForEditor: function (macroAlias, pageId, macroParamDictionary) { + getMacroResultAsHtmlForEditor: function(macroAlias, pageId, macroParamDictionary) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( - "macroApiBaseUrl", - "GetMacroResultAsHtmlForEditor"), { + "macroRenderingApiBaseUrl", + "GetMacroResultAsHtmlForEditor"), + { macroAlias: macroAlias, pageId: pageId, macroParams: macroParamDictionary @@ -67,17 +68,55 @@ function macroResource($q, $http, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( - "macroApiBaseUrl", - "CreatePartialViewMacroWithFile"), { - virtualPath: virtualPath, - filename: filename - } + "macroRenderingApiBaseUrl", + "CreatePartialViewMacroWithFile"), + { + virtualPath: virtualPath, + filename: filename + } ), 'Failed to create macro "' + filename + '"' ); + }, + + createMacro: function(name) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "macroApiBaseUrl", + "Create?name=" + name) + ), + 'Failed to create macro "' + name + '"' + ); + }, + + getPartialViews: function() { + return umbRequestHelper.resourcePromise( + $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetPartialViews"), + "Failed to get partial views") + ); + }, + + getParameterEditors: function() { + return umbRequestHelper.resourcePromise( + $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetParameterEditors"), + "Failed to get parameter editors") + ); + }, + + getById: function(id) { + return umbRequestHelper.resourcePromise( + $http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetById", { "id": id }), "Failed to get macro") + ); + }, + + saveMacro: function(macro) { + return umbRequestHelper.resourcePromise( + $http.post(umbRequestHelper.getApiUrl("macroApiBaseUrl", "Save"), macro) + ); } - }; +}; } angular.module('umbraco.resources').factory('macroResource', macroResource); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/create.html b/src/Umbraco.Web.UI.Client/src/views/macros/create.html new file mode 100644 index 0000000000..a72cd373b2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/create.html @@ -0,0 +1,19 @@ +
+ +
+
Create an item under {{currentNode.name}}
+
+ +
+
+ + + + + + +
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/edit.html b/src/Umbraco.Web.UI.Client/src/views/macros/edit.html new file mode 100644 index 0000000000..ddb5f98781 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/edit.html @@ -0,0 +1,30 @@ +
+
+ + + + + + + + + + + + + + + + + +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.controller.js new file mode 100644 index 0000000000..7dddbb42d1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.controller.js @@ -0,0 +1,27 @@ +(function() { + "use strict"; + + function ParameterEditorController($scope, formHelper) { + + const vm = this; + + vm.submit = submit; + vm.close = close; + + function submit() { + if ($scope.model && $scope.model.submit && formHelper.submitForm({scope: $scope})) { + $scope.model.submit($scope.model); + } + } + + function close() { + if ($scope.model && $scope.model.close) { + $scope.model.close(); + } + } + + } + + angular.module("umbraco").controller("Umbraco.Editors.ParameterEditorController", ParameterEditorController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html new file mode 100644 index 0000000000..402c3c4984 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/infiniteeditors/parameter.html @@ -0,0 +1,58 @@ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' + + +
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.create.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.create.controller.js new file mode 100644 index 0000000000..1745b7b7f6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.create.controller.js @@ -0,0 +1,44 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Macros.CreateController + * @function + * + * @description + * The controller for creating macro items + */ +function MacrosCreateController($scope, $location, macroResource, navigationService, notificationsService, formHelper, appState) { + var vm = this; + + vm.itemKey = ""; + + function createItem() { + + var node = $scope.currentNode; + + macroResource.createMacro(vm.itemKey).then(function (data) { + navigationService.hideMenu(); + + // set new item as active in tree + var currPath = node.path ? node.path : "-1"; + navigationService.syncTree({ tree: "macros", path: currPath + "," + data, forceReload: true, activate: true }); + + // reset form state + formHelper.resetForm({ scope: $scope }); + + // navigate to edit view + var currentSection = appState.getSectionState("currentSection"); + $location.path("/" + currentSection + "/macros/edit/" + data); + + + }, function (err) { + if (err.data && err.data.message) { + notificationsService.error(err.data.message); + navigationService.hideMenu(); + } + }); + } + + vm.createItem = createItem; +} + +angular.module("umbraco").controller("Umbraco.Editors.Macros.CreateController", MacrosCreateController); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js new file mode 100644 index 0000000000..978025ceb4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/macros.edit.controller.js @@ -0,0 +1,155 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Macros.EditController + * @function + * + * @description + * The controller for editing macros. + */ +function MacrosEditController($scope, $q, $routeParams, macroResource, editorState, navigationService, formHelper, contentEditingHelper, localizationService, angularHelper) { + + var vm = this; + + vm.promises = {}; + + vm.page = {}; + vm.page.loading = false; + vm.page.saveButtonState = "init"; + vm.page.menu = {} + + + + function toggleValue(key) { + vm.macro[key] = !vm.macro[key]; + } + + vm.toggle = toggleValue; + + function saveMacro() { + + if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) { + vm.page.saveButtonState = "busy"; + + macroResource.saveMacro(vm.macro).then(function (data) { + formHelper.resetForm({ scope: $scope, notifications: data.notifications }); + bindMacro(data); + vm.page.saveButtonState = "success"; + }, function (error) { + contentEditingHelper.handleSaveError({ + redirectOnFailure: false, + err: error + }); + + vm.page.saveButtonState = "error"; + }); + } + } + + vm.save = saveMacro; + + function setFormDirty() { + var currentForm = angularHelper.getCurrentForm($scope); + + if (currentForm) { + + currentForm.$setDirty(); + } + } + + vm.setDirty = setFormDirty; + + function getPartialViews() { + var deferred = $q.defer(); + + macroResource.getPartialViews().then(function (data) { + deferred.resolve(data); + }, function () { + deferred.reject(); + }); + + return deferred.promise; + } + + function getParameterEditors() { + var deferred = $q.defer(); + + macroResource.getParameterEditors().then(function (data) { + deferred.resolve(data); + }, function () { + deferred.reject(); + }); + + return deferred.promise; + } + + function getMacro() { + var deferred = $q.defer(); + + macroResource.getById($routeParams.id).then(function (data) { + deferred.resolve(data); + }, function () { + deferred.reject(); + }); + + return deferred.promise; + } + + function bindMacro(data) { + vm.macro = data; + editorState.set(vm.macro); + + navigationService.syncTree({ tree: "macros", path: vm.macro.path, forceReload: true }).then(function (syncArgs) { + vm.page.menu.currentNode = syncArgs.node; + }); + } + + function init() { + vm.page.loading = true; + + vm.promises['partialViews'] = getPartialViews(); + vm.promises['parameterEditors'] = getParameterEditors(); + vm.promises['macro'] = getMacro(); + + $q.all(vm.promises).then(function (values) { + var keys = Object.keys(values); + + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + + if (keys[i] === 'partialViews') { + vm.views = values[key]; + } + + if (keys[i] === 'parameterEditors') { + vm.parameterEditors = values[key]; + } + + if (keys[i] === 'macro') { + bindMacro(values[key]); + } + } + + vm.page.loading = false; + }); + + vm.page.navigation = [ + { + "name": "Settings", + "alias": "settings", + "icon": "icon-settings", + "view": "views/macros/views/settings.html", + "active": true + }, + { + "name": "Parameters", + "alias": "parameters", + "icon": "icon-list", + "view": "views/macros/views/parameters.html" + } + ]; + } + + init(); +} + +angular.module("umbraco").controller("Umbraco.Editors.Macros.EditController", MacrosEditController); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.parameters.controller.js b/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.parameters.controller.js new file mode 100644 index 0000000000..851b537c3b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/macro.parameters.controller.js @@ -0,0 +1,78 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.Macros.ParametersController + * @function + * + * @description + * The controller for editing macros parameters + */ +function MacrosParametersController($scope, editorService) { + + $scope.sortableOptions = { + axis: 'y', + containment: 'parent', + cursor: 'move', + items: 'div.umb-stylesheet-rules__listitem', + handle: '.handle', + tolerance: 'pointer', + update: function (e, ui) { + $scope.model.setDirty(); + } + }; + + + $scope.remove = function (parameter, evt) { + evt.preventDefault(); + + $scope.model.macro.parameters = _.without($scope.model.macro.parameters, parameter); + $scope.model.setDirty(); + } + + $scope.add = function (evt) { + evt.preventDefault(); + + openOverlay({}, 'Add parameter', (newParameter) => { + if (!$scope.model.macro.parameters) { + $scope.model.macro.parameters = []; + } + $scope.model.macro.parameters.push(newParameter); + $scope.model.setDirty(); + }); + } + + $scope.edit = function (parameter, evt) { + evt.preventDefault(); + + openOverlay(parameter,'Edit parameter', (newParameter) => { + parameter.key = newParameter.key; + parameter.label = newParameter.label; + parameter.editor = newParameter.editor; + parameter.editor = newParameter.editor; + $scope.model.setDirty(); + }); + } + + function openOverlay(parameter, title, onSubmit) { + + const ruleDialog = { + title: title, + parameter: _.clone(parameter), + editors : $scope.model.parameterEditors, + view: "views/macros/infiniteeditors/parameter.html", + size: "small", + submit: function (model) { + onSubmit(model.parameter); + editorService.close(); + }, + close: function () { + editorService.close(); + } + }; + + editorService.open(ruleDialog); + + } + +} + +angular.module("umbraco").controller("Umbraco.Editors.Macros.ParametersController", MacrosParametersController); diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html new file mode 100644 index 0000000000..91231a49b7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/parameters.html @@ -0,0 +1,32 @@ + + +
+
+
Parameters
+ Define the parameters hat should be available when using his macro +
+
+
+
+
+ +
+ {{parameter.label}} +
+
+ Remove +
+
+
+ + +
+
+
+ +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html new file mode 100644 index 0000000000..59ccf2bc7e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html @@ -0,0 +1,43 @@ + + + + + {{model.macro.id}}
+ {{model.macro.key}} +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 1525dd5808..e266ca01c3 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -169,9 +169,13 @@ namespace Umbraco.Web.Editors controller => controller.GetAllowedChildren(0)) }, { - "macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( + "macroRenderingApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.GetMacroParameters(0)) }, + { + "macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( + controller => controller.Create(null)) + }, { "authenticationApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.PostLogin(null)) diff --git a/src/Umbraco.Web/Editors/MacroController.cs b/src/Umbraco.Web/Editors/MacroRenderingController.cs similarity index 97% rename from src/Umbraco.Web/Editors/MacroController.cs rename to src/Umbraco.Web/Editors/MacroRenderingController.cs index 9780c23504..08ff4ca44b 100644 --- a/src/Umbraco.Web/Editors/MacroController.cs +++ b/src/Umbraco.Web/Editors/MacroRenderingController.cs @@ -27,11 +27,11 @@ namespace Umbraco.Web.Editors /// Session, we don't want it to throw null reference exceptions. /// [PluginController("UmbracoApi")] - public class MacroController : UmbracoAuthorizedJsonController, IRequiresSessionState + public class MacroRenderingController : UmbracoAuthorizedJsonController, IRequiresSessionState { private readonly IVariationContextAccessor _variationContextAccessor; - public MacroController(IVariationContextAccessor variationContextAccessor) + public MacroRenderingController(IVariationContextAccessor variationContextAccessor) { _variationContextAccessor = variationContextAccessor; } diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs new file mode 100644 index 0000000000..5ff2f7bf34 --- /dev/null +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -0,0 +1,320 @@ +namespace Umbraco.Web.Editors +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net; + using System.Net.Http; + using System.Web.Http; + + using Umbraco.Core; + using Umbraco.Core.IO; + using Umbraco.Core.Logging; + using Umbraco.Core.Models; + using Umbraco.Web.Composing; + using Umbraco.Web.Models.ContentEditing; + using Umbraco.Web.Mvc; + using Umbraco.Web.UI; + using Umbraco.Web.WebApi; + using Umbraco.Web.WebApi.Filters; + + using Constants = Umbraco.Core.Constants; + + /// + /// The API controller used for editing dictionary items + /// + [PluginController("UmbracoApi")] + [UmbracoTreeAuthorize(Constants.Trees.Macros)] + public class MacrosController : BackOfficeNotificationsController + { + /// + /// Creates a new macro + /// + /// + /// The name. + /// + /// + /// The . + /// + [HttpPost] + public HttpResponseMessage Create(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + return this.ReturnErrorResponse("Name can not be empty"); + } + + var alias = name.ToSafeAlias(); + + if (this.Services.MacroService.GetByAlias(alias) != null) + { + return this.ReturnErrorResponse("Macro with this alias already exists"); + } + + try + { + var macro = new Macro + { + Alias = alias, + Name = name, + MacroSource = string.Empty, + MacroType = MacroTypes.PartialView + }; + + this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); + + return this.Request.CreateResponse(HttpStatusCode.OK, macro.Id); + } + catch (Exception exception) + { + return this.ReturnErrorResponse("Error creating macro", true, exception); + } + } + + [HttpGet] + public HttpResponseMessage GetById(int id) + { + var macro = this.Services.MacroService.GetById(id); + + if (macro == null) + { + return this.ReturnErrorResponse($"Macro with id {id} does not exist"); + } + + var macroDisplay = new MacroDisplay + { + Alias = macro.Alias, + Id = macro.Id, + Key = macro.Key, + Name = macro.Name, + CacheByPage = macro.CacheByPage, + CacheByUser = macro.CacheByMember, + CachePeriod = macro.CacheDuration, + View = macro.MacroSource, + RenderInEditor = !macro.DontRender, + UseInEditor = macro.UseInEditor, + Path = $"-1,{macro.Id}" + }; + + var parameters = new List(); + + foreach (var param in macro.Properties.Values.OrderBy(x => x.SortOrder)) + { + parameters.Add(new MacroParameterDisplay + { + Editor = param.EditorAlias, + Key = param.Alias, + Label = param.Name, + Id = param.Id + }); + } + + macroDisplay.Parameters = parameters; + + return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay); + } + + [HttpPost] + public HttpResponseMessage Save(MacroDisplay macroDisplay) + { + if (macroDisplay == null) + { + return this.ReturnErrorResponse($"No macro data found in request"); + } + + var macro = this.Services.MacroService.GetById(int.Parse(macroDisplay.Id.ToString())); + + if (macro == null) + { + return this.ReturnErrorResponse($"Macro with id {macroDisplay.Id} does not exist"); + } + + if (macroDisplay.Alias != macro.Alias) + { + var macroByAlias = this.Services.MacroService.GetByAlias(macroDisplay.Alias); + + if (macroByAlias != null) + { + return this.ReturnErrorResponse("Macro with this alias already exists"); + } + } + + macro.Alias = macroDisplay.Alias; + macro.Name = macroDisplay.Name; + macro.CacheByMember = macroDisplay.CacheByUser; + macro.CacheByPage = macroDisplay.CacheByPage; + macro.CacheDuration = macroDisplay.CachePeriod; + macro.DontRender = !macroDisplay.RenderInEditor; + macro.UseInEditor = macroDisplay.UseInEditor; + macro.MacroSource = macroDisplay.View; + macro.MacroType = MacroTypes.PartialView; + macro.Properties.ReplaceAll(macroDisplay.Parameters.Select((x,i) => new MacroProperty(x.Key, x.Label, i, x.Editor))); + + try + { + this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id); + + macroDisplay.Notifications.Clear(); + + macroDisplay.Notifications.Add(new Models.ContentEditing.Notification("Success", "Macro saved", SpeechBubbleIcon.Success)); + + return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay); + } + catch (Exception exception) + { + return this.ReturnErrorResponse("Error creating macro", true, exception); + } + } + + /// + /// Gets a list of available macro partials + /// + /// + /// The . + /// + public HttpResponseMessage GetPartialViews() + { + var views = new List(); + + views.AddRange(this.FindPartialViewsFiles()); + + return this.Request.CreateResponse(HttpStatusCode.OK, views); + } + + /// + /// Gets the available parameter editors + /// + /// + /// The . + /// + public HttpResponseMessage GetParameterEditors() + { + return this.Request.CreateResponse(HttpStatusCode.OK, Current.ParameterEditors); + } + + /// + /// Returns a error response and optionally logs it + /// + /// + /// The error message. + /// + /// + /// Value to indicate if the error needs to be logged + /// + /// + /// The exception to log + /// + /// + /// The . + /// + private HttpResponseMessage ReturnErrorResponse(string message, bool logError = false, Exception exception = null) + { + if (logError && exception != null) + { + this.Logger.Error(exception, message); + } + + return this.Request.CreateNotificationValidationErrorResponse(message); + } + + /// + /// Finds all the macro partials + /// + /// + /// The . + /// + private IEnumerable FindPartialViewsFiles() + { + var files = new List(); + + files.AddRange(this.FindPartialViewFilesInViewsFolder()); + files.AddRange(this.FindPartialViewFilesInPluginFolders()); + + return files; + } + + /// + /// Finds all macro partials in the views folder + /// + /// + /// The . + /// + private IEnumerable FindPartialViewFilesInViewsFolder() + { + var partialsDir = IOHelper.MapPath(SystemDirectories.MacroPartials); + + return this.FindPartialViewFilesInFolder( + partialsDir, + partialsDir, + SystemDirectories.MacroPartials); + } + + /// + /// Finds partial view files in app plugin folders. + /// + /// + /// The . + /// + private IEnumerable FindPartialViewFilesInPluginFolders() + { + var files = new List(); + + var appPluginsFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins)); + + if (!appPluginsFolder.Exists) + { + return files; + } + + foreach (var directory in appPluginsFolder.GetDirectories()) + { + var viewsFolder = directory.GetDirectories("Views"); + if (viewsFolder.Any()) + { + var macroPartials = viewsFolder.First().GetDirectories("MacroPartials"); + if (macroPartials.Any()) + { + files.AddRange(this.FindPartialViewFilesInFolder(macroPartials.First().FullName, macroPartials.First().FullName, SystemDirectories.AppPlugins + "/" + directory.Name + "/Views/MacroPartials")); + } + } + } + + return files; + } + + /// + /// Finds all partial views in a folder and subfolders + /// + /// + /// The org path. + /// + /// + /// The path. + /// + /// + /// The prefix virtual path. + /// + /// + /// The . + /// + private IEnumerable FindPartialViewFilesInFolder(string orgPath, string path, string prefixVirtualPath) + { + var files = new List(); + var dirInfo = new DirectoryInfo(path); + + foreach (var dir in dirInfo.GetDirectories()) + { + files.AddRange(this.FindPartialViewFilesInFolder(orgPath, path + "/" + dir.Name, prefixVirtualPath)); + } + + var fileInfo = dirInfo.GetFiles("*.*"); + + files.AddRange( + fileInfo.Select(file => + prefixVirtualPath.TrimEnd('/') + "/" + (path.Replace(orgPath, string.Empty).Trim('/') + "/" + file.Name).Trim('/'))); + + return files; + } + } +} diff --git a/src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs new file mode 100644 index 0000000000..e84887b88b --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Umbraco.Web.Models.ContentEditing +{ + /// + /// The macro display model + /// + [DataContract(Name = "dictionary", Namespace = "")] + public class MacroDisplay : EntityBasic, INotificationModel + { + /// + /// Initializes a new instance of the class. + /// + public MacroDisplay() + { + this.Notifications = new List(); + this.Parameters = new List(); + } + + /// + [DataMember(Name = "notifications")] + public List Notifications { get; } + + /// + /// Gets or sets a value indicating whether the macro can be used in a rich text editor. + /// + [DataMember(Name = "useInEditor")] + public bool UseInEditor { get; set; } + + /// + /// Gets or sets a value indicating whether the macro should be rendered a rich text editor. + /// + [DataMember(Name = "renderInEditor")] + public bool RenderInEditor { get; set; } + + /// + /// Gets or sets the cache period. + /// + [DataMember(Name = "cachePeriod")] + public int CachePeriod { get; set; } + + /// + /// Gets or sets a value indicating whether the macro should be cached by page + /// + [DataMember(Name = "cacheByPage")] + public bool CacheByPage { get; set; } + + /// + /// Gets or sets a value indicating whether the macro should be cached by user + /// + [DataMember(Name = "cacheByUser")] + public bool CacheByUser { get; set; } + + /// + /// Gets or sets the view. + /// + [DataMember(Name = "view")] + public string View { get; set; } + + /// + /// Gets or sets the parameters. + /// + [DataMember(Name = "parameters")] + public IEnumerable Parameters { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/ContentEditing/MacroParameterDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MacroParameterDisplay.cs new file mode 100644 index 0000000000..2a07dd84ef --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/MacroParameterDisplay.cs @@ -0,0 +1,35 @@ +namespace Umbraco.Web.Models.ContentEditing +{ + using System.Runtime.Serialization; + + /// + /// The macro parameter display. + /// + [DataContract(Name = "parameter", Namespace = "")] + public class MacroParameterDisplay + { + /// + /// Gets or sets the key. + /// + [DataMember(Name = "key")] + public string Key { get; set; } + + /// + /// Gets or sets the label. + /// + [DataMember(Name = "label")] + public string Label { get; set; } + + /// + /// Gets or sets the editor. + /// + [DataMember(Name = "editor")] + public string Editor { get; set; } + + /// + /// Gets or sets the id. + /// + [DataMember(Name = "id")] + public int Id { get; set; } + } +} diff --git a/src/Umbraco.Web/Trees/MacrosTreeController.cs b/src/Umbraco.Web/Trees/MacrosTreeController.cs index 5576c09704..cdbe4bfcf7 100644 --- a/src/Umbraco.Web/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/MacrosTreeController.cs @@ -39,10 +39,7 @@ namespace Umbraco.Web.Trees queryStrings, macro.Name, "icon-settings-alt", - false, - //TODO: Rebuild the macro editor in angular, then we dont need to have this at all (which is just a path to the legacy editor) - "/" + queryStrings.GetValue("application") + "/framed/" + - Uri.EscapeDataString("/umbraco/developer/macros/editMacro.aspx?macroID=" + macro.Id))); + false)); } } @@ -56,11 +53,8 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { //Create the normal create action - menu.Items.Add(Services.TextService, opensDialog: true) - //Since we haven't implemented anything for macros in angular, this needs to be converted to - //use the legacy format - .ConvertLegacyMenuItem(null, "initmacros", queryStrings.GetValue("application")); - + menu.Items.Add(Services.TextService); + //refresh action menu.Items.Add(new RefreshNode(Services.TextService, true)); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index cdfa475a6b..1c1f7d034e 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -125,6 +125,7 @@ + @@ -166,6 +167,8 @@ + + @@ -779,7 +782,7 @@ - + diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index e3fdf8331f..7b591640b5 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -102,7 +102,7 @@ namespace umbraco /// Initializes a new instance of the page for a content. /// /// The content. - /// This is for usage only. + /// This is for usage only. internal page(IContent content, IVariationContextAccessor variationContextAccessor) : this(new PagePublishedContent(content, variationContextAccessor)) { }