From 4545af0a2178264c2ccc5ca048b86a97dd7a9a12 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 15 Nov 2013 16:56:51 +1100 Subject: [PATCH] Boom! container nodes work for both media and content, fixes: U4-3540 When creating a Container type node - the list view shows all children of the item it's being created underneath U4-3541 media tree is not catering for container types --- .../listview/listview.controller.js | 425 +++++++++--------- .../propertyeditors/listview/listview.html | 201 +++++---- src/Umbraco.Web/Editors/ContentController.cs | 12 +- src/Umbraco.Web/Editors/MediaController.cs | 7 +- .../Models/Mapping/ContentModelMapper.cs | 2 +- .../Models/Mapping/MediaModelMapper.cs | 7 +- .../Mapping/TabsAndPropertiesResolver.cs | 16 +- .../Trees/ContentTreeControllerBase.cs | 2 +- 8 files changed, 364 insertions(+), 308 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 401d47f03d..4b8b0b99ef 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -1,221 +1,244 @@ -angular.module("umbraco") - .controller("Umbraco.PropertyEditors.ListViewController", - function ($rootScope, $scope, $routeParams, contentResource, contentTypeResource, notificationsService, iconHelper, dialogService) { +function listViewController($rootScope, $scope, $routeParams, $injector, notificationsService, iconHelper, dialogService) { - $scope.actionInProgress = false; - $scope.listViewResultSet = { - totalPages: 0, - items: [] - }; + //this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content + // that isn't created yet, if we continue this will use the parent id in the route params which isn't what + // we want. NOTE: This is just a safety check since when we scaffold an empty model on the server we remove + // the list view tab entirely when it's new. + if ($routeParams.create) { + $scope.isNew = true; + return; + } - $scope.options = { - pageSize: 10, - pageNumber: 1, - filter: '', - orderBy: 'Id', - orderDirection: "desc" - }; + //Now we need to check if this is for media or content because that will depend on the resources we use + var contentResource, contentTypeResource; + if ($scope.model.config.entityType && $scope.model.config.entityType === "media") { + contentResource = $injector.get('mediaResource'); + contentTypeResource = $injector.get('mediaTypeResource'); + $scope.entityType = "media"; + } + else { + contentResource = $injector.get('contentResource'); + contentTypeResource = $injector.get('contentTypeResource'); + $scope.entityType = "content"; + } + + $scope.isNew = false; + $scope.actionInProgress = false; + $scope.listViewResultSet = { + totalPages: 0, + items: [] + }; + + $scope.options = { + pageSize: 10, + pageNumber: 1, + filter: '', + orderBy: 'Id', + orderDirection: "desc" + }; - $scope.next = function () { - if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) { - $scope.options.pageNumber++; - $scope.reloadView($scope.contentId); - } - }; + $scope.next = function () { + if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) { + $scope.options.pageNumber++; + $scope.reloadView($scope.contentId); + } + }; - $scope.goToPage = function (pageNumber) { - $scope.options.pageNumber = pageNumber + 1; - $scope.reloadView($scope.contentId); - }; + $scope.goToPage = function (pageNumber) { + $scope.options.pageNumber = pageNumber + 1; + $scope.reloadView($scope.contentId); + }; - $scope.sort = function (field) { + $scope.sort = function (field) { - $scope.options.orderBy = field; + $scope.options.orderBy = field; - if ($scope.options.orderDirection === "desc") { - $scope.options.orderDirection = "asc"; - } else { - $scope.options.orderDirection = "desc"; - } + if ($scope.options.orderDirection === "desc") { + $scope.options.orderDirection = "asc"; + } else { + $scope.options.orderDirection = "desc"; + } - $scope.reloadView($scope.contentId); - }; + $scope.reloadView($scope.contentId); + }; - $scope.prev = function () { - if ($scope.options.pageNumber > 1) { - $scope.options.pageNumber--; - $scope.reloadView($scope.contentId); - } - }; + $scope.prev = function () { + if ($scope.options.pageNumber > 1) { + $scope.options.pageNumber--; + $scope.reloadView($scope.contentId); + } + }; - /*Loads the search results, based on parameters set in prev,next,sort and so on*/ - /*Pagination is done by an array of objects, due angularJS's funky way of monitoring state - with simple values */ + /*Loads the search results, based on parameters set in prev,next,sort and so on*/ + /*Pagination is done by an array of objects, due angularJS's funky way of monitoring state + with simple values */ - $scope.reloadView = function (id) { - contentResource.getChildren(id, $scope.options).then(function (data) { + $scope.reloadView = function (id) { + contentResource.getChildren(id, $scope.options).then(function (data) { - $scope.listViewResultSet = data; - $scope.pagination = []; + $scope.listViewResultSet = data; + $scope.pagination = []; - for (var i = $scope.listViewResultSet.totalPages - 1; i >= 0; i--) { - $scope.pagination[i] = { index: i, name: i + 1 }; - } - - if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) { - $scope.options.pageNumber = $scope.listViewResultSet.totalPages; - } - - }); - }; - - $scope.selectAll = function ($event) { - var checkbox = $event.target; - if (!angular.isArray($scope.listViewResultSet.items)) { - return; - } - for (var i = 0; i < $scope.listViewResultSet.items.length; i++) { - var entity = $scope.listViewResultSet.items[i]; - entity.selected = checkbox.checked; - } - }; - - $scope.isSelectedAll = function () { - if (!angular.isArray($scope.listViewResultSet.items)) { - return false; - } - return _.every($scope.listViewResultSet.items, function (item) { - return item.selected; - }); - }; - - $scope.isAnythingSelected = function () { - if (!angular.isArray($scope.listViewResultSet.items)) { - return false; - } - return _.some($scope.listViewResultSet.items, function (item) { - return item.selected; - }); - }; - - $scope.getIcon = function (entry) { - return iconHelper.convertFromLegacyIcon(entry.icon); - }; - - $scope.delete = function () { - var selected = _.filter($scope.listViewResultSet.items, function (item) { - return item.selected; - }); - var total = selected.length; - if (total === 0) { - return; - } - - if (confirm("Sure you want to delete?") == true) { - $scope.actionInProgress = true; - $scope.bulkStatus = "Starting with delete"; - var current = 1; - - for (var i = 0; i < selected.length; i++) { - $scope.bulkStatus = "Deleted doc " + current + " out of " + total + " documents"; - contentResource.deleteById(selected[i].id).then(function (data) { - if (current === total) { - notificationsService.success("Bulk action", "Deleted " + total + "documents"); - $scope.bulkStatus = ""; - $scope.reloadView($scope.contentId); - $scope.actionInProgress = false; - } - current++; - }); - } - } - - }; - - $scope.publish = function () { - var selected = _.filter($scope.listViewResultSet.items, function (item) { - return item.selected; - }); - var total = selected.length; - if (total === 0) { - return; - } - - $scope.actionInProgress = true; - $scope.bulkStatus = "Starting with publish"; - var current = 1; - - for (var i = 0; i < selected.length; i++) { - $scope.bulkStatus = "Publishing " + current + " out of " + total + " documents"; - - contentResource.publishById(selected[i].id) - .then(function (content) { - if (current == total) { - notificationsService.success("Bulk action", "Published " + total + "documents"); - $scope.bulkStatus = ""; - $scope.reloadView($scope.contentId); - $scope.actionInProgress = false; - } - current++; - }, function (err) { - - $scope.bulkStatus = ""; - $scope.reloadView($scope.contentId); - $scope.actionInProgress = false; - - //if there are validation errors for publishing then we need to show them - if (err.status === 400 && err.data && err.data.Message) { - notificationsService.error("Publish error", err.data.Message); - } - else { - dialogService.ysodDialog(err); - } - }); - - } - }; - - $scope.unpublish = function () { - var selected = _.filter($scope.listViewResultSet.items, function (item) { - return item.selected; - }); - var total = selected.length; - if (total === 0) { - return; - } - - $scope.actionInProgress = true; - $scope.bulkStatus = "Starting with publish"; - var current = 1; - - for (var i = 0; i < selected.length; i++) { - $scope.bulkStatus = "Unpublishing " + current + " out of " + total + " documents"; - - contentResource.unPublish(selected[i].id) - .then(function (content) { - - if (current == total) { - notificationsService.success("Bulk action", "Published " + total + "documents"); - $scope.bulkStatus = ""; - $scope.reloadView($scope.contentId); - $scope.actionInProgress = false; - } - - current++; - }); - } - }; - - if ($routeParams.id) { - $scope.pagination = new Array(10); - $scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id); - $scope.reloadView($routeParams.id); - - $scope.contentId = $routeParams.id; + for (var i = $scope.listViewResultSet.totalPages - 1; i >= 0; i--) { + $scope.pagination[i] = { index: i, name: i + 1 }; + } + if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) { + $scope.options.pageNumber = $scope.listViewResultSet.totalPages; } }); + }; + + $scope.selectAll = function ($event) { + var checkbox = $event.target; + if (!angular.isArray($scope.listViewResultSet.items)) { + return; + } + for (var i = 0; i < $scope.listViewResultSet.items.length; i++) { + var entity = $scope.listViewResultSet.items[i]; + entity.selected = checkbox.checked; + } + }; + + $scope.isSelectedAll = function () { + if (!angular.isArray($scope.listViewResultSet.items)) { + return false; + } + return _.every($scope.listViewResultSet.items, function (item) { + return item.selected; + }); + }; + + $scope.isAnythingSelected = function () { + if (!angular.isArray($scope.listViewResultSet.items)) { + return false; + } + return _.some($scope.listViewResultSet.items, function (item) { + return item.selected; + }); + }; + + $scope.getIcon = function (entry) { + return iconHelper.convertFromLegacyIcon(entry.icon); + }; + + $scope.delete = function () { + var selected = _.filter($scope.listViewResultSet.items, function (item) { + return item.selected; + }); + var total = selected.length; + if (total === 0) { + return; + } + + if (confirm("Sure you want to delete?") == true) { + $scope.actionInProgress = true; + $scope.bulkStatus = "Starting with delete"; + var current = 1; + + for (var i = 0; i < selected.length; i++) { + $scope.bulkStatus = "Deleted doc " + current + " out of " + total + " documents"; + contentResource.deleteById(selected[i].id).then(function (data) { + if (current === total) { + notificationsService.success("Bulk action", "Deleted " + total + "documents"); + $scope.bulkStatus = ""; + $scope.reloadView($scope.contentId); + $scope.actionInProgress = false; + } + current++; + }); + } + } + + }; + + $scope.publish = function () { + var selected = _.filter($scope.listViewResultSet.items, function (item) { + return item.selected; + }); + var total = selected.length; + if (total === 0) { + return; + } + + $scope.actionInProgress = true; + $scope.bulkStatus = "Starting with publish"; + var current = 1; + + for (var i = 0; i < selected.length; i++) { + $scope.bulkStatus = "Publishing " + current + " out of " + total + " documents"; + + contentResource.publishById(selected[i].id) + .then(function (content) { + if (current == total) { + notificationsService.success("Bulk action", "Published " + total + "documents"); + $scope.bulkStatus = ""; + $scope.reloadView($scope.contentId); + $scope.actionInProgress = false; + } + current++; + }, function (err) { + + $scope.bulkStatus = ""; + $scope.reloadView($scope.contentId); + $scope.actionInProgress = false; + + //if there are validation errors for publishing then we need to show them + if (err.status === 400 && err.data && err.data.Message) { + notificationsService.error("Publish error", err.data.Message); + } + else { + dialogService.ysodDialog(err); + } + }); + + } + }; + + $scope.unpublish = function () { + var selected = _.filter($scope.listViewResultSet.items, function (item) { + return item.selected; + }); + var total = selected.length; + if (total === 0) { + return; + } + + $scope.actionInProgress = true; + $scope.bulkStatus = "Starting with publish"; + var current = 1; + + for (var i = 0; i < selected.length; i++) { + $scope.bulkStatus = "Unpublishing " + current + " out of " + total + " documents"; + + contentResource.unPublish(selected[i].id) + .then(function (content) { + + if (current == total) { + notificationsService.success("Bulk action", "Published " + total + "documents"); + $scope.bulkStatus = ""; + $scope.reloadView($scope.contentId); + $scope.actionInProgress = false; + } + + current++; + }); + } + }; + + if ($routeParams.id) { + $scope.pagination = new Array(10); + $scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id); + $scope.reloadView($routeParams.id); + + $scope.contentId = $routeParams.id; + + } + +} + +angular.module("umbraco").controller("Umbraco.PropertyEditors.ListViewController", listViewController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 23feb61dc3..4cb351f149 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -1,103 +1,114 @@ - -
-
- +
+ +
- - - - - - - - - - + - - +
+
-
- - - - - - +
- Name - - Last edited - - Updated by -
- - -
- + + + + + + + - - {{result.name}}{{result.updateDate|date:'medium'}} - - {{result.owner.name}}
+ + + + + + + + + - - - + -
  • - {{$index + 1}} -
  • + + + + + + + - - - -
    + + Name + + Last edited + + Updated by + +
    + + +
    +
    -
    - -
    -
    + -
  • - Next -
  • - - +
    + {{result.name}}{{result.updateDate|date:'medium'}} + + {{result.owner.name}} + +
    -
    \ No newline at end of file + + + +
    +
    + + + + + + +
    +
    \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index c7f04e6ac4..65cc5cf6b6 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -95,7 +95,10 @@ namespace Umbraco.Web.Editors /// /// /// - /// + /// + /// If this is a container type, we'll remove the umbContainerView tab for a new item since + /// it cannot actually list children if it doesn't exist yet. + /// public ContentItemDisplay GetEmpty(string contentTypeAlias, int parentId) { var contentType = Services.ContentTypeService.GetContentType(contentTypeAlias); @@ -105,7 +108,12 @@ namespace Umbraco.Web.Editors } var emptyContent = new Content("", parentId, contentType); - return Mapper.Map(emptyContent); + var mapped = Mapper.Map(emptyContent); + + //remove this tab if it exists: umbContainerView + var containerTab = mapped.Tabs.FirstOrDefault(x => x.Alias == "umbContainerView"); + mapped.Tabs = mapped.Tabs.Except(new[] {containerTab}); + return mapped; } /// diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 844d8d5fc8..321704e828 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -152,7 +152,12 @@ namespace Umbraco.Web.Editors } var emptyContent = new Core.Models.Media("", parentId, contentType); - return Mapper.Map(emptyContent); + var mapped = Mapper.Map(emptyContent); + + //remove this tab if it exists: umbContainerView + var containerTab = mapped.Tabs.FirstOrDefault(x => x.Alias == "umbContainerView"); + mapped.Tabs = mapped.Tabs.Except(new[] { containerTab }); + return mapped; } /// diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index a0398328ca..d1bd00d2f3 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -100,7 +100,7 @@ namespace Umbraco.Web.Models.Mapping if (content.ContentType.IsContainer) { - TabsAndPropertiesResolver.AddContainerView(display); + TabsAndPropertiesResolver.AddContainerView(display, "content"); } TabsAndPropertiesResolver.MapGenericProperties( diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index 75e3d0098e..a105048f65 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -61,12 +61,11 @@ namespace Umbraco.Web.Models.Mapping 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.AddContainerView(display, "media"); + } TabsAndPropertiesResolver.MapGenericProperties(media, display); } diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index 62485daae6..b4fcb412c4 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -108,11 +108,17 @@ namespace Umbraco.Web.Models.Mapping } - internal static void AddContainerView(TabbedContentItem display) + /// + /// Adds the container (listview) tab to the document + /// + /// + /// + /// This must be either 'content' or 'media' + internal static void AddContainerView(TabbedContentItem display, string entityType) where TPersisted : IContentBase { var listViewTab = new Tab(); - listViewTab.Alias = "containerView"; + listViewTab.Alias = "umbContainerView"; listViewTab.Label = ui.Text("content", "childItems"); listViewTab.Id = 25; listViewTab.IsActive = true; @@ -124,7 +130,11 @@ namespace Umbraco.Web.Models.Mapping Label = "", Value = null, View = "listview", - HideLabel = true + HideLabel = true, + Config = new Dictionary + { + {"entityType", entityType} + } }); listViewTab.Properties = listViewProperties; diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index 2261d038ec..82d9fcb9b2 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -84,7 +84,7 @@ namespace Umbraco.Web.Trees } //before we get the children we need to see if this is a container node - var current = Services.EntityService.Get(int.Parse(id), UmbracoObjectTypes.Document); + var current = Services.EntityService.Get(int.Parse(id), UmbracoObjectType); if (current != null && current.AdditionalData.ContainsKey("IsContainer") && current.AdditionalData["IsContainer"] is bool && (bool)current.AdditionalData["IsContainer"]) { //no children!