From a39d41b1b7ae06ad342292e7c8653a89f3e220d4 Mon Sep 17 00:00:00 2001 From: perploug Date: Sun, 20 Oct 2013 23:36:26 +0200 Subject: [PATCH] adding media move dialog and support for media containers media containers are disabled currently for UI reasons --- .../src/common/resources/media.resource.js | 47 +++++++++++- .../src/views/media/media.move.controller.js | 38 ++++++++++ .../src/views/media/move.html | 38 ++++++++++ src/Umbraco.Web/Editors/ContentController.cs | 4 +- src/Umbraco.Web/Editors/MediaController.cs | 72 ++++++++++++++++++- .../Models/Mapping/ContentModelMapper.cs | 29 +------- .../Models/Mapping/MediaModelMapper.cs | 15 ++++ .../Mapping/TabsAndPropertiesResolver.cs | 29 +++++++- 8 files changed, 239 insertions(+), 33 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/media/media.move.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/media/move.html diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js index 951a4d182f..71676bab7c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js @@ -61,8 +61,53 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { parentId: args.parentId, idSortOrder: args.sortedIds }), - 'Failed to sort content'); + 'Failed to sort media'); }, + + /** + * @ngdoc method + * @name umbraco.resources.mediaResource#move + * @methodOf umbraco.resources.mediaResource + * + * @description + * Moves a node underneath a new parentId + * + * ##usage + *
+         * mediaResource.move({ parentId: 1244, id: 123 })
+         *    .then(function() {
+         *        alert("node was moved");
+         *    }, function(err){
+         *      alert("node didnt move:" + err.data.Message); 
+         *    });
+         * 
+ * @param {Object} args arguments object + * @param {Int} args.idd the ID of the node to move + * @param {Int} args.parentId the ID of the parent node to move to + * @returns {Promise} resourcePromise object. + * + */ + move: function (args) { + if (!args) { + throw "args cannot be null"; + } + if (!args.parentId) { + throw "args.parentId cannot be null"; + } + if (!args.id) { + throw "args.id cannot be null"; + } + + return umbRequestHelper.resourcePromise( + $http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostMove"), + { + parentId: args.parentId, + id: args.id + }), + 'Failed to move media'); + }, + + /** * @ngdoc method * @name umbraco.resources.mediaResource#getById diff --git a/src/Umbraco.Web.UI.Client/src/views/media/media.move.controller.js b/src/Umbraco.Web.UI.Client/src/views/media/media.move.controller.js new file mode 100644 index 0000000000..8a7d807c59 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/media/media.move.controller.js @@ -0,0 +1,38 @@ +//used for the media picker dialog +angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController", + function ($scope, eventsService, mediaResource, $log) { + var dialogOptions = $scope.$parent.dialogOptions; + + $scope.dialogTreeEventHandler = $({}); + var node = dialogOptions.currentNode; + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){ + args.event.preventDefault(); + args.event.stopPropagation(); + + eventsService.publish("Umbraco.Editors.Media.MoveController.Select", args).then(function(args){ + var c = $(args.event.target.parentElement); + if($scope.selectedEl){ + $scope.selectedEl.find(".temporary").remove(); + $scope.selectedEl.find("i.umb-tree-icon").show(); + } + + c.find("i.umb-tree-icon").hide() + .after(""); + + $scope.target = args.node; + $scope.selectedEl = c; + }); + }); + + $scope.move = function(){ + mediaResource.move({parentId: $scope.target.id, id: node.id}) + .then(function(){ + $scope.error = false; + $scope.success = true; + },function(err){ + $scope.success = false; + $scope.error = err; + }); + }; +}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/media/move.html b/src/Umbraco.Web.UI.Client/src/views/media/move.html new file mode 100644 index 0000000000..ffe8ce58a7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/media/move.html @@ -0,0 +1,38 @@ +
+
+
+ +

+ Choose where to move {{currentNode.name}} to in the tree struture below +

+ +
+

{{error.errorMsg}}

+

{{error.data.Message}}

+
+ +
+

{{currentNode.name}} was moved underneath + {{target.name}}

+ + +
+ +
+ + +
+
+
+ + + +
\ No newline at end of file diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 8cc2c26bd3..6dce2a471b 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -87,9 +87,7 @@ namespace Umbraco.Web.Editors var content = Mapper.Map(foundContent); return content; - -// content.Tabs.ElementAt(0).Properties. - } + } /// /// Gets an empty content item for the diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index d2aca4f1c5..a9e59c6cf4 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -270,6 +270,22 @@ namespace Umbraco.Web.Editors return Request.CreateResponse(HttpStatusCode.OK); } + /// + /// Change the sort order for media + /// + /// + /// + [EnsureUserPermissionForMedia("move.Id")] + public HttpResponseMessage PostMove(MoveOrCopy move) + { + + var toMove = ValidateMoveOrCopy(move); + + Services.MediaService.Move(toMove, move.ParentId); + + return Request.CreateResponse(HttpStatusCode.OK); + } + /// /// Saves content /// @@ -460,7 +476,61 @@ namespace Umbraco.Web.Editors return new HttpResponseMessage(HttpStatusCode.OK); } - + + + /// + /// Ensures the item can be moved/copied to the new location + /// + /// + /// + private IMedia ValidateMoveOrCopy(MoveOrCopy model) + { + if (model == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + var mediaService = Services.MediaService; + var toMove = mediaService.GetById(model.Id); + if (toMove == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + if (model.ParentId < 0) + { + //cannot move if the content item is not allowed at the root + if (toMove.ContentType.AllowedAsRoot == false) + { + throw new HttpResponseException( + Request.CreateValidationErrorResponse(ui.Text("moveOrCopy", "notAllowedAtRoot", Security.CurrentUser))); + } + } + else + { + var parent = mediaService.GetById(model.ParentId); + if (parent == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + //check if the item is allowed under this one + if (parent.ContentType.AllowedContentTypes.Select(x => x.Id).ToArray() + .Any(x => x.Value == toMove.ContentType.Id) == false) + { + throw new HttpResponseException( + Request.CreateValidationErrorResponse(ui.Text("moveOrCopy", "notAllowedByContentType", Security.CurrentUser))); + } + + // Check on paths + if ((string.Format(",{0},", parent.Path)).IndexOf(string.Format(",{0},", toMove.Id), StringComparison.Ordinal) > -1) + { + throw new HttpResponseException( + Request.CreateValidationErrorResponse(ui.Text("moveOrCopy", "notAllowedByPath", Security.CurrentUser))); + } + } + + return toMove; + } /// /// Performs a permissions check for the user to check if it has access to the node based on diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index 1a5b905c00..ed0936dcdf 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -96,7 +96,7 @@ namespace Umbraco.Web.Models.Mapping if (content.ContentType.IsContainer) { - AddContainerView(display); + TabsAndPropertiesResolver.AddContainerView(display); } TabsAndPropertiesResolver.MapGenericProperties( @@ -135,32 +135,7 @@ namespace Umbraco.Web.Models.Mapping }); } - private static void AddContainerView(TabbedContentItem display) - where TPersisted : IContentBase - { - var listViewTab = new Tab(); - listViewTab.Alias = "containerView"; - listViewTab.Label = "Content"; - listViewTab.Id = 25; - listViewTab.IsActive = true; - - var listViewProperties = new List(); - listViewProperties.Add(new ContentPropertyDisplay - { - Alias = string.Format("{0}containerView", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "releaseDate"), - Value = null, - View = "listview", - HideLabel = true - }); - listViewTab.Properties = listViewProperties; - - //Is there a better way? - var tabs = new List>(); - tabs.Add(listViewTab); - tabs.AddRange(display.Tabs); - display.Tabs = tabs; - } + /// /// Gets the published date value for the IContent object diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index 73ec858233..d29bd6321b 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -35,7 +35,10 @@ namespace Umbraco.Web.Models.Mapping expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) + .AfterMap(MapGenericCustomProperties); + /* .AfterMap((media, display) => TabsAndPropertiesResolver.MapGenericProperties(media, display)); + */ //FROM IMedia TO ContentItemBasic config.CreateMap>() @@ -56,5 +59,17 @@ namespace Umbraco.Web.Models.Mapping expression => expression.ResolveUsing>()); } + private static void MapGenericCustomProperties(IMedia media, MediaItemDisplay display) + { + /* + * Should this be added? if so we need some changes in the UI tho. + if (media.ContentType.IsContainer) + { + TabsAndPropertiesResolver.AddContainerView(display); + }*/ + + TabsAndPropertiesResolver.MapGenericProperties(media, display); + } + } } diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index ef22fecb91..eada889d40 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -46,7 +46,7 @@ namespace Umbraco.Web.Models.Mapping params ContentPropertyDisplay[] customProperties) where TPersisted : IContentBase { - + var genericProps = display.Tabs.Single(x => x.Id == 0); @@ -108,6 +108,33 @@ namespace Umbraco.Web.Models.Mapping } + internal static void AddContainerView(TabbedContentItem display) + where TPersisted : IContentBase + { + var listViewTab = new Tab(); + listViewTab.Alias = "containerView"; + listViewTab.Label = "Child items"; + listViewTab.Id = 25; + listViewTab.IsActive = true; + + var listViewProperties = new List(); + listViewProperties.Add(new ContentPropertyDisplay + { + Alias = string.Format("{0}containerView", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = "", + Value = null, + View = "listview", + HideLabel = true + }); + listViewTab.Properties = listViewProperties; + + //Is there a better way? + var tabs = new List>(); + tabs.Add(listViewTab); + tabs.AddRange(display.Tabs); + display.Tabs = tabs; + } + protected override IEnumerable> ResolveCore(IContentBase content) { var aggregateTabs = new List>();