From 599872a310bc9e10822acdfa443df12601bdfed1 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 08:53:32 +0200 Subject: [PATCH 01/18] Created new field in cmsContentType and related models for storing the configuration for a container doc type; implemented configurable page size --- src/Umbraco.Core/Models/ContentTypeBase.cs | 19 ++++++++ src/Umbraco.Core/Models/IContentTypeBase.cs | 5 +++ .../Models/Rdbms/ContentTypeDto.cs | 4 ++ .../Models/Rdbms/MemberTypeReadOnlyDto.cs | 5 +++ .../Factories/ContentTypeFactory.cs | 2 + .../Persistence/Factories/MediaTypeFactory.cs | 2 + .../Factories/MemberTypeFactory.cs | 1 + .../Factories/MemberTypeReadOnlyFactory.cs | 1 + .../Persistence/Mappers/ContentTypeMapper.cs | 1 + .../Persistence/Mappers/MediaTypeMapper.cs | 1 + .../Persistence/Mappers/MemberTypeMapper.cs | 1 + .../Services/EntityXmlSerializer.cs | 3 +- src/Umbraco.Core/Services/PackagingService.cs | 9 ++++ .../common/resources/contenttype.resource.js | 32 ++++++++++++++ .../common/resources/mediatype.resource.js | 32 ++++++++++++++ .../listview/listview.controller.js | 44 ++++++++++--------- .../Editors/ContentTypeController.cs | 16 +++++++ .../Editors/MediaTypeController.cs | 15 ++++++- .../ContentTypeContainerConfiguration.cs | 19 ++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 20 files changed, 191 insertions(+), 22 deletions(-) create mode 100644 src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 5c09deadb8..0333bbcf2b 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -29,6 +29,7 @@ namespace Umbraco.Core.Models private int _creatorId; private bool _allowedAsRoot; private bool _isContainer; + private string _containerConfig; private bool _trashed; private PropertyGroupCollection _propertyGroups; private PropertyTypeCollection _propertyTypes; @@ -72,6 +73,7 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId); private static readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo(x => x.AllowedAsRoot); private static readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo(x => x.IsContainer); + private static readonly PropertyInfo ContainerConfigSelector = ExpressionHelper.GetPropertyInfo(x => x.ContainerConfig); private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed); private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes); private static readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups); @@ -303,6 +305,23 @@ namespace Umbraco.Core.Models } } + /// + /// Gets or Sets a JSON string defining the configuration for this ContentType if set as a container + /// + [DataMember] + public virtual string ContainerConfig + { + get { return _containerConfig; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _containerConfig = value; + return _containerConfig; + }, _containerConfig, ContainerConfigSelector); + } + } + /// /// Boolean indicating whether this ContentType is Trashed or not. /// If ContentType is Trashed it will be located in the Recyclebin. diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index 89fca20b8e..57195762c1 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -43,6 +43,11 @@ namespace Umbraco.Core.Models /// bool IsContainer { get; set; } + /// + /// Gets or Sets a JSON string defining the configuration for this ContentType if set as a container + /// + string ContainerConfig { get; set; } + /// /// Gets or Sets a list of integer Ids of the ContentTypes allowed under the ContentType /// diff --git a/src/Umbraco.Core/Models/Rdbms/ContentTypeDto.cs b/src/Umbraco.Core/Models/Rdbms/ContentTypeDto.cs index 8d163abf44..9651e94e71 100644 --- a/src/Umbraco.Core/Models/Rdbms/ContentTypeDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/ContentTypeDto.cs @@ -39,6 +39,10 @@ namespace Umbraco.Core.Models.Rdbms [Constraint(Default = "0")] public bool IsContainer { get; set; } + [Column("containerConfig")] + [NullSetting(NullSetting = NullSettings.Null)] + public string ContainerConfig { get; set; } + [Column("allowAtRoot")] [Constraint(Default = "0")] public bool AllowAtRoot { get; set; } diff --git a/src/Umbraco.Core/Models/Rdbms/MemberTypeReadOnlyDto.cs b/src/Umbraco.Core/Models/Rdbms/MemberTypeReadOnlyDto.cs index 4833cb33f0..8118ca1bad 100644 --- a/src/Umbraco.Core/Models/Rdbms/MemberTypeReadOnlyDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/MemberTypeReadOnlyDto.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.DatabaseAnnotations; namespace Umbraco.Core.Models.Rdbms { @@ -62,6 +63,10 @@ namespace Umbraco.Core.Models.Rdbms [Column("isContainer")] public bool IsContainer { get; set; } + [Column("containerConfig")] + [NullSetting(NullSetting = NullSettings.Null)] + public string ContainerConfig { get; set; } + [Column("allowAtRoot")] public bool AllowAtRoot { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs index cc9ab387f8..20686269b0 100644 --- a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs @@ -38,6 +38,7 @@ namespace Umbraco.Core.Persistence.Factories CreatorId = dto.ContentTypeDto.NodeDto.UserId.Value, AllowedAsRoot = dto.ContentTypeDto.AllowAtRoot, IsContainer = dto.ContentTypeDto.IsContainer, + ContainerConfig = dto.ContentTypeDto.ContainerConfig, Trashed = dto.ContentTypeDto.NodeDto.Trashed, DefaultTemplateId = dto.TemplateNodeId }; @@ -74,6 +75,7 @@ namespace Umbraco.Core.Persistence.Factories NodeId = entity.Id, AllowAtRoot = entity.AllowedAsRoot, IsContainer = entity.IsContainer, + ContainerConfig = entity.ContainerConfig, NodeDto = BuildNodeDto(entity) }; return contentTypeDto; diff --git a/src/Umbraco.Core/Persistence/Factories/MediaTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/MediaTypeFactory.cs index ee2709a79e..498e35b83d 100644 --- a/src/Umbraco.Core/Persistence/Factories/MediaTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MediaTypeFactory.cs @@ -37,6 +37,7 @@ namespace Umbraco.Core.Persistence.Factories CreatorId = dto.NodeDto.UserId.Value, AllowedAsRoot = dto.AllowAtRoot, IsContainer = dto.IsContainer, + ContainerConfig = dto.ContainerConfig, Trashed = dto.NodeDto.Trashed }; //on initial construction we don't want to have dirty properties tracked @@ -56,6 +57,7 @@ namespace Umbraco.Core.Persistence.Factories NodeId = entity.Id, AllowAtRoot = entity.AllowedAsRoot, IsContainer = entity.IsContainer, + ContainerConfig = entity.ContainerConfig, NodeDto = BuildNodeDto(entity) }; return contentTypeDto; diff --git a/src/Umbraco.Core/Persistence/Factories/MemberTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberTypeFactory.cs index 49feb5f8c8..f37db94c87 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberTypeFactory.cs @@ -32,6 +32,7 @@ namespace Umbraco.Core.Persistence.Factories NodeId = entity.Id, AllowAtRoot = entity.AllowedAsRoot, IsContainer = entity.IsContainer, + ContainerConfig = entity.ContainerConfig, NodeDto = BuildNodeDto(entity) }; return contentTypeDto; diff --git a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs index 2a59f564e2..37f987930e 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs @@ -23,6 +23,7 @@ namespace Umbraco.Core.Persistence.Factories Icon = dto.Icon, Id = dto.NodeId, IsContainer = dto.IsContainer, + ContainerConfig = dto.ContainerConfig, Key = dto.UniqueId.Value, Level = dto.Level, Name = dto.Text, diff --git a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs index 943b42b2ba..c8b619161d 100644 --- a/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/ContentTypeMapper.cs @@ -47,6 +47,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.ContainerConfig, dto => dto.ContainerConfig); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs index 70e4b5c861..912ae19e2f 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MediaTypeMapper.cs @@ -47,6 +47,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.ContainerConfig, dto => dto.ContainerConfig); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs index 69a5190b46..192c3ee090 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MemberTypeMapper.cs @@ -48,6 +48,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.Description, dto => dto.Description); CacheMap(src => src.Icon, dto => dto.Icon); CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.ContainerConfig, dto => dto.ContainerConfig); CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); } } diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index c260b10418..b56d854044 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -305,7 +305,8 @@ namespace Umbraco.Core.Services new XElement("Thumbnail", contentType.Thumbnail), new XElement("Description", contentType.Description), new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()), - new XElement("IsListView", contentType.IsContainer.ToString())); + new XElement("IsListView", contentType.IsContainer.ToString()), + new XElement("ContainerConfig", contentType.ContainerConfig.ToString())); var masterContentType = contentType.CompositionAliases().FirstOrDefault(); if (masterContentType != null) diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 47310ab1c3..44551096c5 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -423,8 +423,17 @@ namespace Umbraco.Core.Services //NOTE IsListView is a new property in the package xml so we need to verify it exists before using it. var isListView = infoElement.Element("IsListView"); if (isListView != null) + { contentType.IsContainer = isListView.Value.InvariantEquals("true"); + //NOTE ContainerConfig is a new property in the package xml so we need to verify it exists before using it. + var containerConfig = infoElement.Element("ContainerConfig"); + if (containerConfig != null) + { + contentType.ContainerConfig = containerConfig.Value; + } + } + UpdateContentTypesAllowedTemplates(contentType, infoElement.Element("AllowedTemplates"), defaultTemplateElement); UpdateContentTypesTabs(contentType, documentType.Element("Tabs")); UpdateContentTypesProperties(contentType, documentType.Element("GenericProperties")); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js index 16a948bd4f..afacf4c88d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js @@ -68,6 +68,38 @@ function contentTypeResource($q, $http, umbRequestHelper) { "GetAllowedChildren", [{ contentId: contentId }])), 'Failed to retrieve data for content id ' + contentId); + }, + + /** + * @ngdoc method + * @name umbraco.resources.contentTypeResource#getContainerConfig + * @methodOf umbraco.resources.contentTypeResource + * + * @description + * Returns a JSON structure for configuration of the container content type + * + * ##usage + *
+         * contentTypeResource.getContainerConfig(1234)
+         *    .then(function(config) {
+         *      $scope.options = {
+         *         pageSize: config.pageSize,
+         *      };
+         *    });
+         * 
+ * @param {Int} contentId id of the content item to retrive the container config for + * @returns {Promise} resourcePromise object. + * + */ + getContainerConfig: function (contentId) { + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "contentTypeApiBaseUrl", + "GetContainerConfig", + [{ contentId: contentId }])), + 'Failed to retrieve container config data for content id ' + contentId); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js index 94699d4195..9f4ac83c11 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js @@ -35,6 +35,38 @@ function mediaTypeResource($q, $http, umbRequestHelper) { "GetAllowedChildren", [{ contentId: mediaId }])), 'Failed to retrieve allowed types for media id ' + mediaId); + }, + + /** + * @ngdoc method + * @name umbraco.resources.mediaTypeResource#getContainerConfig + * @methodOf umbraco.resources.mediaTypeResource + * + * @description + * Returns a JSON structure for configuration of the container content type + * + * ##usage + *
+         * mediaTypeResource.getContainerConfig(1234)
+         *    .then(function(config) {
+         *      $scope.options = {
+         *         pageSize: config.pageSize,
+         *      };
+         *    });
+         * 
+ * @param {Int} contentId id of the content item to retrive the container config for + * @returns {Promise} resourcePromise object. + * + */ + getContainerConfig: function (contentId) { + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "mediaTypeApiBaseUrl", + "GetContainerConfig", + [{ contentId: contentId }])), + 'Failed to retrieve container config data for media id ' + contentId); } }; 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 379504cf71..8789dc1adb 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 @@ -29,14 +29,19 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific items: [] }; - $scope.options = { - pageSize: 10, - pageNumber: 1, - filter: '', - orderBy: 'UpdateDate', - orderDirection: "desc" - }; + // Retrieve the container configuration for the content type and set options before presenting initial view + contentTypeResource.getContainerConfig($routeParams.id) + .then(function (config) { + $scope.options = { + pageSize: config.pageSize, + pageNumber: 1, + filter: '', + orderBy: 'UpdateDate', + orderDirection: "desc" + }; + $scope.initView(); + }); $scope.next = function () { if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) { @@ -54,14 +59,12 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.options.orderBy = field; - if ($scope.options.orderDirection === "desc") { $scope.options.orderDirection = "asc"; } else { $scope.options.orderDirection = "desc"; } - $scope.reloadView($scope.contentId); }; @@ -72,6 +75,17 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }; + $scope.initView = function () { + if ($routeParams.id) { + $scope.pagination = new Array(10); + $scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id); + $scope.reloadView($routeParams.id); + + $scope.contentId = $routeParams.id; + $scope.isTrashed = $routeParams.id === "-20" || $routeParams.id === "-21"; + } + }; + /*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 */ @@ -80,7 +94,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific contentResource.getChildren(id, $scope.options).then(function (data) { $scope.listViewResultSet = data; - $scope.pagination = []; + $scope.pagination = []; for (var i = $scope.listViewResultSet.totalPages - 1; i >= 0; i--) { $scope.pagination[i] = { index: i, name: i + 1 }; @@ -236,16 +250,6 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }; - if ($routeParams.id) { - $scope.pagination = new Array(10); - $scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id); - $scope.reloadView($routeParams.id); - - $scope.contentId = $routeParams.id; - $scope.isTrashed = $routeParams.id === "-20" || $routeParams.id === "-21"; - - } - } angular.module("umbraco").controller("Umbraco.PropertyEditors.ListViewController", listViewController); \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 10c4d31a6a..a0bc01e9a1 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -12,6 +12,7 @@ using Umbraco.Web.WebApi; using System.Linq; using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; +using Newtonsoft.Json; namespace Umbraco.Web.Editors { @@ -86,6 +87,21 @@ namespace Umbraco.Web.Editors return basics; } + /// + /// Returns the container configuration JSON structure for the content item id passed in + /// + /// + public ContentTypeContainerConfiguration GetContainerConfig(int contentId) + { + var contentItem = Services.ContentService.GetById(contentId); + if (contentItem == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); + } + // TODO: This should really be centralized and used anywhere globalization applies. internal string TranslateItem(string text) { diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index bb27ef7b61..74b262b8f4 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -61,11 +61,24 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - return contentItem.ContentType.AllowedContentTypes .Select(x => Services.ContentTypeService.GetMediaType((int) x.Id.Value)) .Select(Mapper.Map); + } + /// + /// Returns the container configuration JSON structure for the content item id passed in + /// + /// + public JsonNetResult GetContainerConfig(int contentId) + { + var contentItem = Services.ContentService.GetById(contentId); + if (contentItem == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs new file mode 100644 index 0000000000..291b5e1f0c --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace Umbraco.Web.Models.ContentEditing +{ + /// + /// A model representing the configuration for a content type defined as a list container + /// + [DataContract(Name = "config", Namespace = "")] + public class ContentTypeContainerConfiguration + { + /// + /// The page size for the list + /// + [DataMember(Name = "pageSize", IsRequired = true)] + [Required] + public int PageSize { get; set; } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index aba7c4d109..ef318cb9af 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -300,6 +300,7 @@ + From 988e025d12b3329f556f3b92cae4b16bed3e93ca Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 09:03:31 +0200 Subject: [PATCH 02/18] Refactored content and media type controllers to have inherit from a common abstract class, that implements the retrieval of the container config --- .../ContentAndMediaTypeBaseController.cs | 47 +++++++++++++++++++ .../Editors/ContentTypeController.cs | 19 +------- .../Editors/MediaTypeController.cs | 20 ++------ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 4 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs diff --git a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs new file mode 100644 index 0000000000..8fb752916f --- /dev/null +++ b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs @@ -0,0 +1,47 @@ +using System.Net; +using System.Web.Http; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Mvc; +using Newtonsoft.Json; + +namespace Umbraco.Web.Editors +{ + /// + /// Am abstract API controller providing functionality used for dealing with content and media types + /// + [PluginController("UmbracoApi")] + public abstract class ContentAndMediaTypeBaseController : UmbracoAuthorizedJsonController + { + /// + /// Constructor + /// + public ContentAndMediaTypeBaseController() + : this(UmbracoContext.Current) + { + } + + /// + /// Constructor + /// + /// + public ContentAndMediaTypeBaseController(UmbracoContext umbracoContext) + : base(umbracoContext) + { + } + + /// + /// Returns the container configuration JSON structure for the content item id passed in + /// + /// + public ContentTypeContainerConfiguration GetContainerConfig(int contentId) + { + var contentItem = Services.ContentService.GetById(contentId); + if (contentItem == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index a0bc01e9a1..03d248ec32 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -24,8 +24,8 @@ namespace Umbraco.Web.Editors /// /// An API controller used for dealing with content types /// - [PluginController("UmbracoApi")] - public class ContentTypeController : UmbracoAuthorizedJsonController + [PluginController("UmbracoApi")] + public class ContentTypeController : ContentAndMediaTypeBaseController { private ICultureDictionary _cultureDictionary; @@ -87,21 +87,6 @@ namespace Umbraco.Web.Editors return basics; } - /// - /// Returns the container configuration JSON structure for the content item id passed in - /// - /// - public ContentTypeContainerConfiguration GetContainerConfig(int contentId) - { - var contentItem = Services.ContentService.GetById(contentId); - if (contentItem == null) - { - throw new HttpResponseException(HttpStatusCode.NotFound); - } - - return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); - } - // TODO: This should really be centralized and used anywhere globalization applies. internal string TranslateItem(string text) { diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index 74b262b8f4..92e83d9732 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Web.Http; using AutoMapper; +using Newtonsoft.Json; using Umbraco.Core.Models; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; @@ -19,8 +20,8 @@ namespace Umbraco.Web.Editors /// /// An API controller used for dealing with media types /// - [PluginController("UmbracoApi")] - public class MediaTypeController : UmbracoAuthorizedJsonController + [PluginController("UmbracoApi")] + public class MediaTypeController : ContentAndMediaTypeBaseController { /// /// Constructor @@ -65,20 +66,5 @@ namespace Umbraco.Web.Editors .Select(x => Services.ContentTypeService.GetMediaType((int) x.Id.Value)) .Select(Mapper.Map); } - - /// - /// Returns the container configuration JSON structure for the content item id passed in - /// - /// - public JsonNetResult GetContainerConfig(int contentId) - { - var contentItem = Services.ContentService.GetById(contentId); - if (contentItem == null) - { - throw new HttpResponseException(HttpStatusCode.NotFound); - } - - return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); - } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index ef318cb9af..8a43f35b83 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -292,6 +292,7 @@ + From 332220acc4ff70783599551c3215391eb67b8de2 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 10:28:52 +0200 Subject: [PATCH 03/18] Amend of container page size from structure tab of document type editing screen --- src/Umbraco.Tests/Umbraco.Tests.csproj | 3 ++ .../controls/ContentTypeControlNew.ascx | 4 ++ .../ContentTypeControlNew.ascx.designer.cs | 2 - .../controls/ContentTypeControlNew.ascx.cs | 53 +++++++++++++++++-- src/umbraco.cms/businesslogic/ContentType.cs | 38 +++++++++++-- src/umbraco.cms/businesslogic/media/Media.cs | 7 +-- src/umbraco.cms/businesslogic/web/Document.cs | 13 ++--- 7 files changed, 102 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index f2c7f45449..65e6661ce6 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -698,6 +698,9 @@ + + + xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /D diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index 6c8d26b4d6..e8e148a0dc 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -80,6 +80,10 @@
+ + + + diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs index c17c27becf..582c67837d 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs @@ -11,7 +11,5 @@ namespace Umbraco.Web.UI.Umbraco.Controls { public partial class ContentTypeControlNew { - - } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 0f1fc3a090..dbdf9610bc 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -31,6 +31,8 @@ using umbraco.presentation; using umbraco.BasePages; using ContentType = umbraco.cms.businesslogic.ContentType; using PropertyType = Umbraco.Core.Models.PropertyType; +using Umbraco.Web.Models.ContentEditing; +using Newtonsoft.Json; namespace umbraco.controls { @@ -295,12 +297,13 @@ namespace umbraco.controls _contentType.ContentTypeItem.Name = txtName.Text; _contentType.ContentTypeItem.Alias = txtAlias.Text; // raw, contentType.Alias takes care of it - _contentType.ContentTypeItem.Icon = tb_icon.Value; + _contentType.ContentTypeItem.Icon = tb_icon.Value; _contentType.ContentTypeItem.Description = description.Text; //_contentType.ContentTypeItem.Thumbnail = ddlThumbnails.SelectedValue; _contentType.ContentTypeItem.AllowedAsRoot = allowAtRoot.Checked; - _contentType.ContentTypeItem.IsContainer = cb_isContainer.Checked; - + _contentType.ContentTypeItem.IsContainer = cb_isContainer.Checked; + _contentType.ContentTypeItem.ContainerConfig = GetProvidedContainerConfigAsJsonString(); + int i = 0; var ids = SaveAllowedChildTypes(); _contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort {Id = new Lazy(() => x), SortOrder = i++}); @@ -354,6 +357,35 @@ namespace umbraco.controls Page.ExecuteRegisteredAsyncTasks(); } + /// + /// Helper to retrive the strongly typed container configuration from the persisted JSON string + /// + /// Container configuration as JSON string + private ContentTypeContainerConfiguration GetContentTypeContainerConfigurationFromJsonString(string config) + { + return JsonConvert.DeserializeObject(config); + } + + /// + /// Helper to parse the container configuration provided by the form fields into a JSON string for persistance + /// + /// Container configuration as JSON string + private string GetProvidedContainerConfigAsJsonString() + { + int pageSize; + if (!int.TryParse(txtContainerConfigPageSize.Text, out pageSize)) + { + pageSize = 10; // - default page size if none configured + } + + var containerConfig = new ContentTypeContainerConfiguration + { + PageSize = pageSize, + }; + + return JsonConvert.SerializeObject(containerConfig); + } + /// /// Loads the current ContentType from the id found in the querystring. /// The correct type is loaded based on editing location (DocumentType, MediaType or MemberType). @@ -562,6 +594,16 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); allowAtRoot.Checked = _contentType.AllowAtRoot; cb_isContainer.Checked = _contentType.IsContainerContentType; + + if (!string.IsNullOrEmpty(_contentType.ContainerConfig)) + { + var containerConfig = GetContentTypeContainerConfigurationFromJsonString(_contentType.ContainerConfig); + txtContainerConfigPageSize.Text = containerConfig.PageSize.ToString(); + } + else + { + txtContainerConfigPageSize.Text = string.Empty; + } } private int[] SaveAllowedChildTypes() @@ -1334,7 +1376,10 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected global::umbraco.uicontrols.PropertyPanel pp_newTab; protected global::umbraco.uicontrols.PropertyPanel pp_isContainer; - protected global::System.Web.UI.WebControls.CheckBox cb_isContainer; + protected global::System.Web.UI.WebControls.CheckBox cb_isContainer; + + protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigPageSize; + protected global::System.Web.UI.WebControls.TextBox txtContainerConfigPageSize; /// /// txtNewTab control. diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 58dbde48a3..9b344c50bf 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -60,12 +60,13 @@ namespace umbraco.cms.businesslogic /// /// /// + /// containerConfig /// /// This is like creating a ContentType node using optimized mode but this lets you set /// all of the properties that are initialized normally from the database. /// This is used for performance reasons. /// - internal ContentType(int id, string alias, string icon, string thumbnail, int? masterContentType, bool? isContainer) + internal ContentType(int id, string alias, string icon, string thumbnail, int? masterContentType, bool? isContainer, string containerConfig) : base(id, true) { _alias = alias; @@ -77,6 +78,8 @@ namespace umbraco.cms.businesslogic if (isContainer.HasValue) _isContainerContentType = isContainer.Value; + + _containerConfig = containerConfig; } internal ContentType(IContentTypeComposition contentType) : base(contentType) @@ -90,7 +93,7 @@ namespace umbraco.cms.businesslogic protected internal const string m_SQLOptimizedGetAll = @" SELECT id, createDate, trashed, parentId, nodeObjectType, nodeUser, level, path, sortOrder, uniqueID, text, - allowAtRoot, isContainer, Alias,icon,thumbnail,description + allowAtRoot, isContainer, containerConfig, Alias,icon,thumbnail,description FROM umbracoNode INNER JOIN cmsContentType ON umbracoNode.id = cmsContentType.nodeId WHERE nodeObjectType = @nodeObjectType"; @@ -250,6 +253,7 @@ namespace umbraco.cms.businesslogic private string _thumbnail; List m_masterContentTypes; private bool _isContainerContentType; + private string _containerConfig; private List _allowedChildContentTypeIDs; private List _virtualTabs; @@ -426,6 +430,32 @@ namespace umbraco.cms.businesslogic } } + /// + /// Get or Sets the container configuration of the Content Type for types defined as containers + /// + public string ContainerConfig + { + get { return _containerConfig; } + set + { + _containerConfig = value; + + //This switches between using new vs. legacy api. + //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. + if (ContentTypeItem == null) + { + SqlHelper.ExecuteNonQuery( + "update cmsContentType set containerConfig = @containerConfig where nodeId = @id", + SqlHelper.CreateParameter("@containerConfig", value), + SqlHelper.CreateParameter("@id", Id)); + } + else + { + ContentTypeItem.ContainerConfig = _containerConfig; + } + } + } + /// /// Gets or sets the 'allow at root' boolean /// @@ -1103,6 +1133,7 @@ namespace umbraco.cms.businesslogic _alias = contentType.Alias; _iconurl = contentType.Icon; _isContainerContentType = contentType.IsContainer; + _containerConfig = contentType.ContainerConfig; _allowAtRoot = contentType.AllowedAsRoot; _thumbnail = contentType.Thumbnail; _description = contentType.Description; @@ -1116,6 +1147,7 @@ namespace umbraco.cms.businesslogic _alias = dr.GetString("Alias"); _iconurl = dr.GetString("icon"); _isContainerContentType = dr.GetBoolean("isContainer"); + _containerConfig = dr.GetString("containerConfig"); _allowAtRoot = dr.GetBoolean("allowAtRoot"); if (!dr.IsNull("thumbnail")) @@ -1161,7 +1193,7 @@ namespace umbraco.cms.businesslogic } // TODO: Load master content types - using (var dr = SqlHelper.ExecuteReader("Select allowAtRoot, isContainer, Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id) + using (var dr = SqlHelper.ExecuteReader("Select allowAtRoot, isContainer, containerConfig, Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id) ) { if (dr.Read()) diff --git a/src/umbraco.cms/businesslogic/media/Media.cs b/src/umbraco.cms/businesslogic/media/Media.cs index 073977aca5..1b1208b44b 100644 --- a/src/umbraco.cms/businesslogic/media/Media.cs +++ b/src/umbraco.cms/businesslogic/media/Media.cs @@ -361,7 +361,8 @@ namespace umbraco.cms.businesslogic.media , dr.GetString("description") , null , dr.GetInt("contentTypeId") - , dr.GetBoolean("isContainer")); + , dr.GetBoolean("isContainer") + , dr.GetString("containerConfig")); } #endregion @@ -383,10 +384,10 @@ namespace umbraco.cms.businesslogic.media [Obsolete("Obsolete, This method is no longer needed", false)] private void SetupMediaForTree(Guid uniqueId, int level, int parentId, int user, string path, string text, DateTime createDate, string icon, bool hasChildren, string contentTypeAlias, string contentTypeThumb, - string contentTypeDesc, int? masterContentType, int contentTypeId, bool isContainer) + string contentTypeDesc, int? masterContentType, int contentTypeId, bool isContainer, string containerConfig) { SetupNodeForTree(uniqueId, _objectType, level, parentId, user, path, text, createDate, hasChildren); - ContentType = new ContentType(contentTypeId, contentTypeAlias, icon, contentTypeThumb, masterContentType, isContainer); + ContentType = new ContentType(contentTypeId, contentTypeAlias, icon, contentTypeThumb, masterContentType, isContainer, containerConfig); ContentTypeIcon = icon; } diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 44d22945c5..6bd6e1f028 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -93,7 +93,7 @@ namespace umbraco.cms.businesslogic.web Content.UpdateDate, Content.UpdateDate, Content.ContentType.Icon, hasChildren, Content.ContentType.Alias, Content.ContentType.Thumbnail, Content.ContentType.Description, null, Content.ContentType.Id, - templateId, Content.ContentType.IsContainer); + templateId, Content.ContentType.IsContainer, Content.ContentType.ContainerConfig); var tmpReleaseDate = Content.ReleaseDate.HasValue ? Content.ReleaseDate.Value : new DateTime(); var tmpExpireDate = Content.ExpireDate.HasValue ? Content.ExpireDate.Value : new DateTime(); @@ -1493,10 +1493,11 @@ namespace umbraco.cms.businesslogic.web , dr.GetString("alias") , dr.GetString("thumbnail") , dr.GetString("description") - , null + , null , dr.GetInt("contentTypeId") - , dr.GetInt("templateId") - , dr.GetBoolean("isContainer")); + , dr.GetInt("templateId") + , dr.GetBoolean("isContainer") + , dr.GetString("containerConfig")); if (!dr.IsNull("releaseDate")) _release = dr.GetDateTime("releaseDate"); @@ -1516,7 +1517,7 @@ namespace umbraco.cms.businesslogic.web private void SetupDocumentForTree(Guid uniqueId, int level, int parentId, int creator, int writer, bool publish, string path, string text, DateTime createDate, DateTime updateDate, DateTime versionDate, string icon, bool hasChildren, string contentTypeAlias, string contentTypeThumb, - string contentTypeDesc, int? masterContentType, int contentTypeId, int templateId, bool isContainer) + string contentTypeDesc, int? masterContentType, int contentTypeId, int templateId, bool isContainer, string containerConfig) { SetupNodeForTree(uniqueId, _objectType, level, parentId, creator, path, text, createDate, hasChildren); @@ -1524,7 +1525,7 @@ namespace umbraco.cms.businesslogic.web _published = publish; _updated = updateDate; _template = templateId; - ContentType = new ContentType(contentTypeId, contentTypeAlias, icon, contentTypeThumb, null, isContainer); + ContentType = new ContentType(contentTypeId, contentTypeAlias, icon, contentTypeThumb, null, isContainer, containerConfig); ContentTypeIcon = icon; VersionDate = versionDate; } From df04a9069861814d2511cd91b0e188e4deff0a6b Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 10:35:51 +0200 Subject: [PATCH 04/18] Only save container config if provided --- .../controls/ContentTypeControlNew.ascx | 2 +- .../controls/ContentTypeControlNew.ascx.cs | 21 ++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index e8e148a0dc..9d89374e99 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -81,7 +81,7 @@
- + diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index dbdf9610bc..ede906d1aa 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -372,18 +372,29 @@ namespace umbraco.controls /// Container configuration as JSON string private string GetProvidedContainerConfigAsJsonString() { + var configProvided = false; + int pageSize; - if (!int.TryParse(txtContainerConfigPageSize.Text, out pageSize)) + if (int.TryParse(txtContainerConfigPageSize.Text, out pageSize)) + { + configProvided = true; + } + else { pageSize = 10; // - default page size if none configured } - var containerConfig = new ContentTypeContainerConfiguration + if (configProvided) { - PageSize = pageSize, - }; + var containerConfig = new ContentTypeContainerConfiguration + { + PageSize = pageSize, + }; - return JsonConvert.SerializeObject(containerConfig); + return JsonConvert.SerializeObject(containerConfig); + } + + return string.Empty; } /// From ef2c7e2d3a31cb55205175e14fc5d97be9405342 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 14:40:55 +0200 Subject: [PATCH 05/18] Ensured that the default container options are used if no configuration has been defined --- .../listview/listview.controller.js | 19 ++++++++++++------- .../ContentAndMediaTypeBaseController.cs | 7 ++++++- 2 files changed, 18 insertions(+), 8 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 8789dc1adb..ff1da85a0c 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 @@ -29,16 +29,21 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific items: [] }; + // Set default default options (i.e. those if no container configuration has been saved) + $scope.options = { + pageSize: 10, + pageNumber: 1, + filter: '', + orderBy: 'UpdateDate', + orderDirection: "desc" + }; + // Retrieve the container configuration for the content type and set options before presenting initial view contentTypeResource.getContainerConfig($routeParams.id) .then(function (config) { - $scope.options = { - pageSize: config.pageSize, - pageNumber: 1, - filter: '', - orderBy: 'UpdateDate', - orderDirection: "desc" - }; + if (typeof(config.pageSize) !== 'undefined') { + $scope.options.pageSize = config.pageSize; + } $scope.initView(); }); diff --git a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs index 8fb752916f..1601d6f0f1 100644 --- a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs +++ b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs @@ -41,7 +41,12 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); + if (!string.IsNullOrEmpty(contentItem.ContentType.ContainerConfig)) + { + return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); + } + + return null; } } } \ No newline at end of file From 5ad8ebfa6e46226156c07a8aa05129d692324a59 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 15:04:15 +0200 Subject: [PATCH 06/18] Store, retrieve and use default order by and direction for list container document type --- .../listview/listview.controller.js | 8 +++++ .../controls/ContentTypeControlNew.ascx | 14 +++++++- .../ContentTypeContainerConfiguration.cs | 16 ++++++++- .../controls/ContentTypeControlNew.ascx.cs | 33 ++++++++++++++++--- 4 files changed, 64 insertions(+), 7 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 ff1da85a0c..52aa7fc278 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 @@ -45,6 +45,14 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.options.pageSize = config.pageSize; } + if (typeof (config.orderBy) !== 'undefined') { + $scope.options.orderBy = config.orderBy; + } + + if (typeof (config.orderDirection) !== 'undefined') { + $scope.options.orderDirection = config.orderDirection; + } + $scope.initView(); }); diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index 9d89374e99..560e1377cd 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -81,9 +81,21 @@
- + + + + + + + + + + Ascending + Descending + + diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs index 291b5e1f0c..8c7771bd51 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs @@ -12,8 +12,22 @@ namespace Umbraco.Web.Models.ContentEditing /// /// The page size for the list /// - [DataMember(Name = "pageSize", IsRequired = true)] + [DataMember(Name = "pageSize")] [Required] public int PageSize { get; set; } + + /// + /// The default order by column for the list + /// + [DataMember(Name = "orderBy")] + [Required] + public string OrderBy { get; set; } + + /// + /// The default order direction for the list + /// + [DataMember(Name = "orderDirection")] + [Required] + public string OrderDirection { get; set; } } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index ede906d1aa..c6dd4090c0 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Web; using System.Web.Mvc; using System.Threading.Tasks; -using System.Web; using System.Web.Routing; using System.Web.UI; using System.Web.UI.HtmlControls; @@ -374,14 +373,25 @@ namespace umbraco.controls { var configProvided = false; - int pageSize; + // Set defaults for saving if not all fields are provided + var pageSize = 10; + var orderBy = "UpdateDate"; + var orderDirection = "desc"; if (int.TryParse(txtContainerConfigPageSize.Text, out pageSize)) { configProvided = true; } - else + + if (!string.IsNullOrEmpty(txtContainerConfigOrderBy.Text)) { - pageSize = 10; // - default page size if none configured + orderBy = txtContainerConfigOrderBy.Text; + configProvided = true; + } + + if (ddlContainerConfigOrderDirection.SelectedIndex > 0) + { + orderDirection = ddlContainerConfigOrderDirection.SelectedItem.Value; + configProvided = true; } if (configProvided) @@ -389,6 +399,8 @@ namespace umbraco.controls var containerConfig = new ContentTypeContainerConfiguration { PageSize = pageSize, + OrderBy = orderBy, + OrderDirection = orderDirection, }; return JsonConvert.SerializeObject(containerConfig); @@ -610,10 +622,15 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { var containerConfig = GetContentTypeContainerConfigurationFromJsonString(_contentType.ContainerConfig); txtContainerConfigPageSize.Text = containerConfig.PageSize.ToString(); + txtContainerConfigOrderBy.Text = containerConfig.OrderBy; + ddlContainerConfigOrderDirection.SelectedIndex = -1; + ddlContainerConfigOrderDirection.Items.FindByValue(containerConfig.OrderDirection).Selected = true; } else { txtContainerConfigPageSize.Text = string.Empty; + txtContainerConfigOrderBy.Text = string.Empty; + ddlContainerConfigOrderDirection.SelectedIndex = -1; } } @@ -1390,7 +1407,13 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected global::System.Web.UI.WebControls.CheckBox cb_isContainer; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigPageSize; - protected global::System.Web.UI.WebControls.TextBox txtContainerConfigPageSize; + protected global::System.Web.UI.WebControls.TextBox txtContainerConfigPageSize; + + protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderBy; + protected global::System.Web.UI.WebControls.TextBox txtContainerConfigOrderBy; + + protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderDirection; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderDirection; /// /// txtNewTab control. From eec6fe2115fc3f2a0c69d2080474eb869680c003 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 15:09:35 +0200 Subject: [PATCH 07/18] Changed selection of default order by column for container document types to drop down list --- .../umbraco/controls/ContentTypeControlNew.ascx | 7 ++++++- .../umbraco/controls/ContentTypeControlNew.ascx.cs | 13 ++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index 560e1377cd..79f71d6e2e 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -86,7 +86,12 @@ - + + + Node Name + Last Edited Date + Updated By + diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index c6dd4090c0..c3862fb5f3 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -382,9 +382,9 @@ namespace umbraco.controls configProvided = true; } - if (!string.IsNullOrEmpty(txtContainerConfigOrderBy.Text)) + if (ddlContainerConfigOrderBy.SelectedIndex > 0) { - orderBy = txtContainerConfigOrderBy.Text; + orderBy = ddlContainerConfigOrderBy.SelectedItem.Value; configProvided = true; } @@ -618,19 +618,18 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); allowAtRoot.Checked = _contentType.AllowAtRoot; cb_isContainer.Checked = _contentType.IsContainerContentType; + ddlContainerConfigOrderBy.SelectedIndex = -1; + ddlContainerConfigOrderDirection.SelectedIndex = -1; if (!string.IsNullOrEmpty(_contentType.ContainerConfig)) { var containerConfig = GetContentTypeContainerConfigurationFromJsonString(_contentType.ContainerConfig); txtContainerConfigPageSize.Text = containerConfig.PageSize.ToString(); - txtContainerConfigOrderBy.Text = containerConfig.OrderBy; - ddlContainerConfigOrderDirection.SelectedIndex = -1; + ddlContainerConfigOrderBy.Items.FindByValue(containerConfig.OrderBy).Selected = true; ddlContainerConfigOrderDirection.Items.FindByValue(containerConfig.OrderDirection).Selected = true; } else { txtContainerConfigPageSize.Text = string.Empty; - txtContainerConfigOrderBy.Text = string.Empty; - ddlContainerConfigOrderDirection.SelectedIndex = -1; } } @@ -1410,7 +1409,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected global::System.Web.UI.WebControls.TextBox txtContainerConfigPageSize; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderBy; - protected global::System.Web.UI.WebControls.TextBox txtContainerConfigOrderBy; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderBy; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderDirection; protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderDirection; From 4d19826d98110063deb5a9f25be75d4328e60121 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 15:36:18 +0200 Subject: [PATCH 08/18] Store and retrieval of flags for allowing bulk publish, unpublish and/or delete on container doc types --- .../controls/ContentTypeControlNew.ascx | 63 +++++++++++++------ .../ContentTypeContainerConfiguration.cs | 21 +++++++ .../controls/ContentTypeControlNew.ascx.cs | 49 ++++++++++++--- 3 files changed, 106 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index 79f71d6e2e..9c8adfb236 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -81,26 +81,53 @@
- - - +
+ + + - - - - Node Name - Last Edited Date - Updated By - - + + + + Node Name + Last Edited Date + Updated By + + + + + + + Ascending + Descending + + + + + + + Yes + No + + + + + + + Yes + No + + + + + + + Yes + No + + +
- - - - Ascending - Descending - - diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs index 8c7771bd51..10249cebfb 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs @@ -29,5 +29,26 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "orderDirection")] [Required] public string OrderDirection { get; set; } + + /// + /// Flag for whether bulk publishing is allowed + /// + [DataMember(Name = "allowBulkPublish")] + [Required] + public bool AllowBulkPublish { get; set; } + + /// + /// Flag for whether bulk unpublishing is allowed + /// + [DataMember(Name = "allowBulkUnpublish")] + [Required] + public bool AllowBulkUnpublish { get; set; } + + /// + /// Flag for whether bulk deletion is allowed + /// + [DataMember(Name = "allowBulkDelete")] + [Required] + public bool AllowBulkDelete { get; set; } } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index c3862fb5f3..4bfb3b7b4f 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -7,26 +7,18 @@ using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; -using System.Threading.Tasks; using System.Web.Routing; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Strings; using Umbraco.Web.UI.Controls; -using umbraco.BusinessLogic; -using umbraco.cms.businesslogic; -using umbraco.cms.businesslogic.propertytype; using umbraco.cms.businesslogic.web; using umbraco.cms.helpers; using umbraco.controls.GenericProperties; using Umbraco.Core.IO; -using umbraco.presentation; using umbraco.BasePages; using ContentType = umbraco.cms.businesslogic.ContentType; using PropertyType = Umbraco.Core.Models.PropertyType; @@ -377,6 +369,9 @@ namespace umbraco.controls var pageSize = 10; var orderBy = "UpdateDate"; var orderDirection = "desc"; + var allowBulkPublish = true; + var allowBulkUnpublish = true; + var allowBulkDelete = true; if (int.TryParse(txtContainerConfigPageSize.Text, out pageSize)) { configProvided = true; @@ -394,6 +389,24 @@ namespace umbraco.controls configProvided = true; } + if (ddlContainerConfigAllowBulkPublish.SelectedIndex > 0) + { + allowBulkPublish = ddlContainerConfigAllowBulkPublish.SelectedIndex == 1; + configProvided = true; + } + + if (ddlContainerConfigAllowBulkUnpublish.SelectedIndex > 0) + { + allowBulkUnpublish = ddlContainerConfigAllowBulkUnpublish.SelectedIndex == 1; + configProvided = true; + } + + if (ddlContainerConfigAllowBulkDelete.SelectedIndex > 0) + { + allowBulkDelete = ddlContainerConfigAllowBulkDelete.SelectedIndex == 1; + configProvided = true; + } + if (configProvided) { var containerConfig = new ContentTypeContainerConfiguration @@ -401,6 +414,9 @@ namespace umbraco.controls PageSize = pageSize, OrderBy = orderBy, OrderDirection = orderDirection, + AllowBulkPublish = allowBulkPublish, + AllowBulkUnpublish = allowBulkUnpublish, + AllowBulkDelete = allowBulkDelete, }; return JsonConvert.SerializeObject(containerConfig); @@ -620,12 +636,18 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); ddlContainerConfigOrderBy.SelectedIndex = -1; ddlContainerConfigOrderDirection.SelectedIndex = -1; + ddlContainerConfigAllowBulkPublish.SelectedIndex = -1; + ddlContainerConfigAllowBulkUnpublish.SelectedIndex = -1; + ddlContainerConfigAllowBulkDelete.SelectedIndex = -1; if (!string.IsNullOrEmpty(_contentType.ContainerConfig)) { var containerConfig = GetContentTypeContainerConfigurationFromJsonString(_contentType.ContainerConfig); txtContainerConfigPageSize.Text = containerConfig.PageSize.ToString(); ddlContainerConfigOrderBy.Items.FindByValue(containerConfig.OrderBy).Selected = true; ddlContainerConfigOrderDirection.Items.FindByValue(containerConfig.OrderDirection).Selected = true; + ddlContainerConfigAllowBulkPublish.SelectedIndex = containerConfig.AllowBulkPublish ? 1 : 2; + ddlContainerConfigAllowBulkUnpublish.SelectedIndex = containerConfig.AllowBulkUnpublish ? 1 : 2; + ddlContainerConfigAllowBulkDelete.SelectedIndex = containerConfig.AllowBulkDelete ? 1 : 2; } else { @@ -1412,7 +1434,16 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderBy; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderDirection; - protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderDirection; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderDirection; + + protected global::umbraco.uicontrols.PropertyPanel pp_allowBulkPublish; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigAllowBulkPublish; + + protected global::umbraco.uicontrols.PropertyPanel pp_allowBulkUnpublish; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigAllowBulkUnpublish; + + protected global::umbraco.uicontrols.PropertyPanel pp_allowBulkDelete; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigAllowBulkDelete; /// /// txtNewTab control. From e1cf3306385f7a2cd50368d1c76c9fc7d0c74ee7 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 27 Jul 2014 20:52:06 +0200 Subject: [PATCH 09/18] Display or otherwise the bulk action buttons (publish, unpublish and delete) according to the container config --- .../listview/listview.controller.js | 19 +++++++++++++++++-- .../propertyeditors/listview/listview.html | 6 +++--- 2 files changed, 20 insertions(+), 5 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 52aa7fc278..db99f5c6e0 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 @@ -29,13 +29,16 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific items: [] }; - // Set default default options (i.e. those if no container configuration has been saved) + // Set "default default" options (i.e. those if no container configuration has been saved) $scope.options = { pageSize: 10, pageNumber: 1, filter: '', orderBy: 'UpdateDate', - orderDirection: "desc" + orderDirection: "desc", + allowBulkPublish: true, + allowBulkUnpublish: true, + allowBulkDelete: true, }; // Retrieve the container configuration for the content type and set options before presenting initial view @@ -53,6 +56,18 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.options.orderDirection = config.orderDirection; } + if (typeof (config.allowBulkPublish) !== 'undefined') { + $scope.options.allowBulkPublish = config.allowBulkPublish; + } + + if (typeof (config.allowBulkUnpublish) !== 'undefined') { + $scope.options.allowBulkUnpublish = config.allowBulkUnpublish; + } + + if (typeof (config.allowBulkDelete) !== 'undefined') { + $scope.options.allowBulkDelete = config.allowBulkDelete; + } + $scope.initView(); }); 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 57b7eff7c9..8bcd3dd968 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 @@ -23,17 +23,17 @@ -
+ -
+ -
+
Delete From 50f1a995e9f2017bc8652499e71895250589d679 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Mon, 28 Jul 2014 22:07:57 +0200 Subject: [PATCH 10/18] Set up headings with localization for container list view custom columns --- .../listview/listview.controller.js | 78 +++++++++++++++---- .../propertyeditors/listview/listview.html | 41 ++++++---- .../controls/ContentTypeControlNew.ascx | 23 +++--- .../ContentAndMediaTypeBaseController.cs | 64 ++++++++++++++- .../ContentTypeContainerConfiguration.cs | 26 +++++-- .../controls/ContentTypeControlNew.ascx.cs | 29 +++++-- 6 files changed, 203 insertions(+), 58 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 db99f5c6e0..4a86da02bc 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 @@ -34,37 +34,40 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific pageSize: 10, pageNumber: 1, filter: '', - orderBy: 'UpdateDate', + orderBy: 'updateDate', orderDirection: "desc", allowBulkPublish: true, allowBulkUnpublish: true, allowBulkDelete: true, + additionalColumnAliases: ['UpdateDate', 'Owner'], + additionalColumnHeaders: ['Last edited', 'Updated by'], + additionalColumnLocalizationKeys: ['defaultdialogs_lastEdited', 'content_updatedBy'] }; // Retrieve the container configuration for the content type and set options before presenting initial view contentTypeResource.getContainerConfig($routeParams.id) .then(function (config) { - if (typeof(config.pageSize) !== 'undefined') { + if (typeof config.pageSize !== 'undefined') { $scope.options.pageSize = config.pageSize; } - - if (typeof (config.orderBy) !== 'undefined') { + if (typeof config.additionalColumnAliases !== 'undefined') { + $scope.options.additionalColumnAliases = config.additionalColumnAliases.split(','); + $scope.options.additionalColumnHeaders = config.additionalColumnHeaders.split(','); + $scope.options.additionalColumnLocalizationKeys = config.additionalColumnLocalizationKeys.split(','); + } + if (typeof config.orderBy !== 'undefined') { $scope.options.orderBy = config.orderBy; } - - if (typeof (config.orderDirection) !== 'undefined') { + if (typeof config.orderDirection !== 'undefined') { $scope.options.orderDirection = config.orderDirection; } - - if (typeof (config.allowBulkPublish) !== 'undefined') { + if (typeof config.allowBulkPublish !== 'undefined') { $scope.options.allowBulkPublish = config.allowBulkPublish; } - - if (typeof (config.allowBulkUnpublish) !== 'undefined') { + if (typeof config.allowBulkUnpublish !== 'undefined') { $scope.options.allowBulkUnpublish = config.allowBulkUnpublish; } - - if (typeof (config.allowBulkDelete) !== 'undefined') { + if (typeof config.allowBulkDelete !== 'undefined') { $scope.options.allowBulkDelete = config.allowBulkDelete; } @@ -120,7 +123,6 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.reloadView = function (id) { contentResource.getChildren(id, $scope.options).then(function (data) { - $scope.listViewResultSet = data; $scope.pagination = []; @@ -135,6 +137,56 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific }); }; + $scope.getColumnName = function (index) { + return $scope.options.additionalColumnHeaders[index]; + }; + + $scope.getColumnLocalizationKey = function (index) { + return $scope.options.additionalColumnLocalizationKeys[index]; + }; + + $scope.getPropertyValue = function (alias, result) { + + // Camel-case the alias + alias = alias.charAt(0).toLowerCase() + alias.slice(1); + + // First try to pull the value directly from the alias (e.g. updatedBy) + var value = result[alias]; + + // If this returns an object, look for the name property of that (e.g. owner.name) + if (value === Object(value)) { + value = value['name']; + } + + // If we've got nothing yet, look at a user defined property + if (typeof value === 'undefined') { + value = $scope.getCustomPropertyValue(alias, result.properties); + } + + // Return what we've got + return value; + + }; + + $scope.getCustomPropertyValue = function (alias, properties) { + var value = ''; + var index = 0; + var foundAlias = false; + for (var i = 0; i < properties.length; i++) { + if (properties[i].alias == alias) { + foundAlias = true; + break; + } + index++; + } + + if (foundAlias) { + value = properties[index].value; + } + + return value; + }; + //assign debounce method to the search to limit the queries $scope.search = _.debounce(function () { $scope.options.pageNumber = 1; 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 8bcd3dd968..d6f419d1e0 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 @@ -49,16 +49,23 @@ - - - Name - - - Last edited - - - Updated by - + + + + + Name + + + + + + + {{getColumnName($index)}} + {{getColumnName($index)}} + + + +
@@ -74,16 +81,16 @@ - - + + - {{result.name}} - {{result.updateDate|date:'medium'}} - + {{result.name}} - {{result.owner.name}} - + + + {{getPropertyValue(alias, result)}} + diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index 9c8adfb236..1c1e4cc625 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -82,20 +82,19 @@
- + - - - - Node Name - Last Edited Date - Updated By - + + + + + + - + Ascending @@ -103,7 +102,7 @@ - + Yes @@ -111,7 +110,7 @@ - + Yes @@ -119,7 +118,7 @@ - + Yes diff --git a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs index 1601d6f0f1..ecb9175b97 100644 --- a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs +++ b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs @@ -1,8 +1,12 @@ -using System.Net; +using System; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; using System.Web.Http; +using Newtonsoft.Json; +using Umbraco.Core; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; -using Newtonsoft.Json; namespace Umbraco.Web.Editors { @@ -35,7 +39,7 @@ namespace Umbraco.Web.Editors /// public ContentTypeContainerConfiguration GetContainerConfig(int contentId) { - var contentItem = Services.ContentService.GetById(contentId); + var contentItem = Services.ContentService.GetById(contentId); if (contentItem == null) { throw new HttpResponseException(HttpStatusCode.NotFound); @@ -43,7 +47,59 @@ namespace Umbraco.Web.Editors if (!string.IsNullOrEmpty(contentItem.ContentType.ContainerConfig)) { - return JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); + var containerConfig = JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); + + // Populate the column headings and localization keys + if (!string.IsNullOrEmpty(containerConfig.AdditionalColumnAliases)) + { + var aliases = containerConfig.AdditionalColumnAliases.Split(','); + var headings = new string[aliases.Length]; + var localizationKeys = new string[aliases.Length]; + + // Find all the properties for doc types that might be in the list + var allowedContentTypeIds = contentItem.ContentType.AllowedContentTypes + .Select(x => x.Id.Value) + .ToArray(); + var allPropertiesOfAllowedContentTypes = Services.ContentTypeService + .GetAllContentTypes(allowedContentTypeIds) + .SelectMany(x => x.PropertyTypes) + .ToList(); + + for (int i = 0; i < aliases.Length; i++) + { + // Try to find heading from custom property (getting the name from the alias) + // - need to look in children of the current content's content type + var property = allPropertiesOfAllowedContentTypes + .FirstOrDefault(x => x.Alias == aliases[i].ToFirstLower()); + if (property != null) + { + headings[i] = property.Name; + } + else if (aliases[i] == "UpdateDate") + { + // Special case to restore hard-coded column titles + headings[i] = "Last edited"; + localizationKeys[i] = "defaultdialogs_lastEdited"; + } + else if (aliases[i] == "Owner") + { + // Special case to restore hard-coded column titles (2) + headings[i] = "Updated by"; + localizationKeys[i] = "content_updatedBy"; + } + else + { + // Otherwise just sentence case the alias + headings[i] = aliases[i].ToFirstUpper().SplitPascalCasing(); + localizationKeys[i] = "content_" + aliases[i].ToFirstLower(); + } + } + + containerConfig.AdditionalColumnHeaders = string.Join(",", headings); + containerConfig.AdditionalColumnLocalizationKeys = string.Join(",", localizationKeys); + } + + return containerConfig; } return null; diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs index 10249cebfb..7fc3c19dc8 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs @@ -13,42 +13,56 @@ namespace Umbraco.Web.Models.ContentEditing /// The page size for the list ///
[DataMember(Name = "pageSize")] - [Required] public int PageSize { get; set; } + /// + /// The aliases additional columns displayed after the node name in the list + /// + [DataMember(Name = "additionalColumnAliases")] + public string AdditionalColumnAliases { get; set; } + + /// + /// The headers for the additional columns displayed after the node name in the list + /// + /// This isn't persisted, but is calculated from the aliases when passed to the UI + [DataMember(Name = "additionalColumnHeaders")] + public string AdditionalColumnHeaders { get; set; } + + /// + /// The localization keys for the additional columns displayed after the node name in the list + /// + /// This isn't persisted, but is calculated from the aliases when passed to the UI + [DataMember(Name = "additionalColumnLocalizationKeys")] + public string AdditionalColumnLocalizationKeys { get; set; } + /// /// The default order by column for the list /// [DataMember(Name = "orderBy")] - [Required] public string OrderBy { get; set; } /// /// The default order direction for the list /// [DataMember(Name = "orderDirection")] - [Required] public string OrderDirection { get; set; } /// /// Flag for whether bulk publishing is allowed /// [DataMember(Name = "allowBulkPublish")] - [Required] public bool AllowBulkPublish { get; set; } /// /// Flag for whether bulk unpublishing is allowed /// [DataMember(Name = "allowBulkUnpublish")] - [Required] public bool AllowBulkUnpublish { get; set; } /// /// Flag for whether bulk deletion is allowed /// [DataMember(Name = "allowBulkDelete")] - [Required] public bool AllowBulkDelete { get; set; } } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 4bfb3b7b4f..3156cf5cdb 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -367,6 +367,7 @@ namespace umbraco.controls // Set defaults for saving if not all fields are provided var pageSize = 10; + var additionalColumns = "UpdateDate,Owner"; var orderBy = "UpdateDate"; var orderDirection = "desc"; var allowBulkPublish = true; @@ -377,9 +378,15 @@ namespace umbraco.controls configProvided = true; } - if (ddlContainerConfigOrderBy.SelectedIndex > 0) + if (!string.IsNullOrEmpty(txtContainerConfigAdditionalColumns.Text)) { - orderBy = ddlContainerConfigOrderBy.SelectedItem.Value; + additionalColumns = txtContainerConfigAdditionalColumns.Text; + configProvided = true; + } + + if (!string.IsNullOrEmpty(txtContainerConfigOrderBy.Text)) + { + orderBy = txtContainerConfigOrderBy.Text; configProvided = true; } @@ -412,6 +419,7 @@ namespace umbraco.controls var containerConfig = new ContentTypeContainerConfiguration { PageSize = pageSize, + AdditionalColumnAliases = additionalColumns, OrderBy = orderBy, OrderDirection = orderDirection, AllowBulkPublish = allowBulkPublish, @@ -419,7 +427,13 @@ namespace umbraco.controls AllowBulkDelete = allowBulkDelete, }; - return JsonConvert.SerializeObject(containerConfig); + // Serialize the object ignoring nulls so the calculated property AdditionalColumnHeadings is not persisted + return JsonConvert.SerializeObject(containerConfig, + Formatting.None, + new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }); } return string.Empty; @@ -634,7 +648,6 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); allowAtRoot.Checked = _contentType.AllowAtRoot; cb_isContainer.Checked = _contentType.IsContainerContentType; - ddlContainerConfigOrderBy.SelectedIndex = -1; ddlContainerConfigOrderDirection.SelectedIndex = -1; ddlContainerConfigAllowBulkPublish.SelectedIndex = -1; ddlContainerConfigAllowBulkUnpublish.SelectedIndex = -1; @@ -643,7 +656,8 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { var containerConfig = GetContentTypeContainerConfigurationFromJsonString(_contentType.ContainerConfig); txtContainerConfigPageSize.Text = containerConfig.PageSize.ToString(); - ddlContainerConfigOrderBy.Items.FindByValue(containerConfig.OrderBy).Selected = true; + txtContainerConfigAdditionalColumns.Text = containerConfig.AdditionalColumnAliases; + txtContainerConfigOrderBy.Text = containerConfig.OrderBy; ddlContainerConfigOrderDirection.Items.FindByValue(containerConfig.OrderDirection).Selected = true; ddlContainerConfigAllowBulkPublish.SelectedIndex = containerConfig.AllowBulkPublish ? 1 : 2; ddlContainerConfigAllowBulkUnpublish.SelectedIndex = containerConfig.AllowBulkUnpublish ? 1 : 2; @@ -1430,8 +1444,11 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigPageSize; protected global::System.Web.UI.WebControls.TextBox txtContainerConfigPageSize; + protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigAdditionalColumns; + protected global::System.Web.UI.WebControls.TextBox txtContainerConfigAdditionalColumns; + protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderBy; - protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderBy; + protected global::System.Web.UI.WebControls.TextBox txtContainerConfigOrderBy; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderDirection; protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderDirection; From 180e93a3bf7cd5baee010193fa1281137f705bc9 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Mon, 28 Jul 2014 22:34:30 +0200 Subject: [PATCH 11/18] Refactor of ContentTypeContainerConfiguration to use a collection instead of multiple delimited strings --- .../listview/listview.controller.js | 17 ++++---- .../propertyeditors/listview/listview.html | 12 +++--- .../ContentAndMediaTypeBaseController.cs | 41 ++++++++++--------- .../ContentTypeContainerConfiguration.cs | 37 ++++++++++------- 4 files changed, 58 insertions(+), 49 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 4a86da02bc..c22316872b 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 @@ -39,9 +39,10 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific allowBulkPublish: true, allowBulkUnpublish: true, allowBulkDelete: true, - additionalColumnAliases: ['UpdateDate', 'Owner'], - additionalColumnHeaders: ['Last edited', 'Updated by'], - additionalColumnLocalizationKeys: ['defaultdialogs_lastEdited', 'content_updatedBy'] + additionalColumns: [ + { alias: 'UpdateDate', header: 'Last edited', localizationKey: 'defaultdialogs_lastEdited' }, + { alias: 'Owner', header: 'Last edited', localizationKey: 'content_updatedBy' } + ] }; // Retrieve the container configuration for the content type and set options before presenting initial view @@ -50,10 +51,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific if (typeof config.pageSize !== 'undefined') { $scope.options.pageSize = config.pageSize; } - if (typeof config.additionalColumnAliases !== 'undefined') { - $scope.options.additionalColumnAliases = config.additionalColumnAliases.split(','); - $scope.options.additionalColumnHeaders = config.additionalColumnHeaders.split(','); - $scope.options.additionalColumnLocalizationKeys = config.additionalColumnLocalizationKeys.split(','); + if (typeof config.additionalColumns !== 'undefined') { + $scope.options.additionalColumns = config.additionalColumns; } if (typeof config.orderBy !== 'undefined') { $scope.options.orderBy = config.orderBy; @@ -138,11 +137,11 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific }; $scope.getColumnName = function (index) { - return $scope.options.additionalColumnHeaders[index]; + return $scope.options.additionalColumns[index].header; }; $scope.getColumnLocalizationKey = function (index) { - return $scope.options.additionalColumnLocalizationKeys[index]; + return $scope.options.additionalColumns[index].localizationKey; }; $scope.getPropertyValue = function (alias, result) { 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 d6f419d1e0..f133ce11b6 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 @@ -58,10 +58,10 @@ - - - {{getColumnName($index)}} - {{getColumnName($index)}} + + + {{getColumnName($index)}} + {{getColumnName($index)}} @@ -87,8 +87,8 @@ {{result.name}} - - {{getPropertyValue(alias, result)}} + + {{getPropertyValue(column.alias, result)}} diff --git a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs index ecb9175b97..193938cf30 100644 --- a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs +++ b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Text.RegularExpressions; @@ -48,14 +49,11 @@ namespace Umbraco.Web.Editors if (!string.IsNullOrEmpty(contentItem.ContentType.ContainerConfig)) { var containerConfig = JsonConvert.DeserializeObject(contentItem.ContentType.ContainerConfig); + containerConfig.AdditionalColumns = new List(); - // Populate the column headings and localization keys + // Populate the column headings and localization keys if (!string.IsNullOrEmpty(containerConfig.AdditionalColumnAliases)) { - var aliases = containerConfig.AdditionalColumnAliases.Split(','); - var headings = new string[aliases.Length]; - var localizationKeys = new string[aliases.Length]; - // Find all the properties for doc types that might be in the list var allowedContentTypeIds = contentItem.ContentType.AllowedContentTypes .Select(x => x.Id.Value) @@ -65,38 +63,43 @@ namespace Umbraco.Web.Editors .SelectMany(x => x.PropertyTypes) .ToList(); - for (int i = 0; i < aliases.Length; i++) + foreach (var alias in containerConfig.AdditionalColumnAliases.Split(',')) { + var column = new ContentTypeContainerConfiguration.AdditionalColumnDetail + { + Alias = alias, + }; + // Try to find heading from custom property (getting the name from the alias) // - need to look in children of the current content's content type var property = allPropertiesOfAllowedContentTypes - .FirstOrDefault(x => x.Alias == aliases[i].ToFirstLower()); + .FirstOrDefault(x => x.Alias == alias.ToFirstLower()); if (property != null) { - headings[i] = property.Name; + column.Header = property.Name; + column.LocalizationKey = string.Empty; } - else if (aliases[i] == "UpdateDate") + else if (alias == "UpdateDate") { // Special case to restore hard-coded column titles - headings[i] = "Last edited"; - localizationKeys[i] = "defaultdialogs_lastEdited"; + column.Header = "Last edited"; + column.LocalizationKey = "defaultdialogs_lastEdited"; } - else if (aliases[i] == "Owner") + else if (alias == "Owner") { // Special case to restore hard-coded column titles (2) - headings[i] = "Updated by"; - localizationKeys[i] = "content_updatedBy"; + column.Header = "Updated by"; + column.LocalizationKey = "content_updatedBy"; } else { // Otherwise just sentence case the alias - headings[i] = aliases[i].ToFirstUpper().SplitPascalCasing(); - localizationKeys[i] = "content_" + aliases[i].ToFirstLower(); + column.Header = alias.ToFirstUpper().SplitPascalCasing(); + column.LocalizationKey = "content_" + alias.ToFirstLower(); } - } - containerConfig.AdditionalColumnHeaders = string.Join(",", headings); - containerConfig.AdditionalColumnLocalizationKeys = string.Join(",", localizationKeys); + containerConfig.AdditionalColumns.Add(column); + } } return containerConfig; diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs index 7fc3c19dc8..70184d6d32 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; namespace Umbraco.Web.Models.ContentEditing @@ -20,20 +21,6 @@ namespace Umbraco.Web.Models.ContentEditing ///
[DataMember(Name = "additionalColumnAliases")] public string AdditionalColumnAliases { get; set; } - - /// - /// The headers for the additional columns displayed after the node name in the list - /// - /// This isn't persisted, but is calculated from the aliases when passed to the UI - [DataMember(Name = "additionalColumnHeaders")] - public string AdditionalColumnHeaders { get; set; } - - /// - /// The localization keys for the additional columns displayed after the node name in the list - /// - /// This isn't persisted, but is calculated from the aliases when passed to the UI - [DataMember(Name = "additionalColumnLocalizationKeys")] - public string AdditionalColumnLocalizationKeys { get; set; } /// /// The default order by column for the list @@ -64,5 +51,25 @@ namespace Umbraco.Web.Models.ContentEditing /// [DataMember(Name = "allowBulkDelete")] public bool AllowBulkDelete { get; set; } + + /// + /// The column details for the additional columns displayed after the node name in the list + /// + /// This isn't persisted, but is calculated from the aliases when passed to the UI + [DataMember(Name = "additionalColumns")] + public IList AdditionalColumns { get; set; } + + [DataContract(Namespace = "")] + public class AdditionalColumnDetail + { + [DataMember(Name = "alias")] + public string Alias { get; set; } + + [DataMember(Name = "header")] + public string Header { get; set; } + + [DataMember(Name = "localizationKey")] + public string LocalizationKey { get; set; } + } } } From eba2ed842b449e093102cbb140d06c0be0034a03 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Mon, 28 Jul 2014 22:46:18 +0200 Subject: [PATCH 12/18] Formatting of dates in list view --- .../propertyeditors/listview/listview.controller.js | 9 +++++++++ 1 file changed, 9 insertions(+) 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 c22316872b..fe79893084 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 @@ -162,11 +162,20 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific value = $scope.getCustomPropertyValue(alias, result.properties); } + // If we have a date, format it + if (isDate(value)) { + value = value.substring(0, value.length - 3); + } + // Return what we've got return value; }; + isDate = function (val) { + return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/); + }; + $scope.getCustomPropertyValue = function (alias, properties) { var value = ''; var index = 0; From 222f8b87442e806d173b2f84f01a3822f0c76e9a Mon Sep 17 00:00:00 2001 From: AndyButland Date: Mon, 28 Jul 2014 23:08:20 +0200 Subject: [PATCH 13/18] Prevented and removed visual indication of sorting by custom columns --- .../src/less/listview.less | 7 +++++++ .../listview/listview.controller.js | 17 +++++++++-------- .../propertyeditors/listview/listview.html | 6 +++--- .../ContentAndMediaTypeBaseController.cs | 6 ++++-- .../ContentTypeContainerConfiguration.cs | 3 +++ 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/listview.less b/src/Umbraco.Web.UI.Client/src/less/listview.less index 13e3853458..0e37893226 100644 --- a/src/Umbraco.Web.UI.Client/src/less/listview.less +++ b/src/Umbraco.Web.UI.Client/src/less/listview.less @@ -82,6 +82,13 @@ color: @black } +.umb-listview table a.no-sort { + cursor: default; +} +.umb-listview table a.no-sort:hover { + text-decoration: none; +} + .umb-listview .icon-star { color: @grayLight } 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 fe79893084..7cc4643aa4 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 @@ -85,17 +85,18 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.reloadView($scope.contentId); }; - $scope.sort = function (field) { + $scope.sort = function (field, allow) { + if (allow) { + $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 () { 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 f133ce11b6..b5e3335804 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 @@ -52,15 +52,15 @@ - + Name - - {{getColumnName($index)}} + + {{getColumnName($index)}} {{getColumnName($index)}} diff --git a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs index 193938cf30..c289b80888 100644 --- a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs +++ b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs @@ -67,7 +67,9 @@ namespace Umbraco.Web.Editors { var column = new ContentTypeContainerConfiguration.AdditionalColumnDetail { - Alias = alias, + Alias = alias, + LocalizationKey = string.Empty, + AllowSorting = true, }; // Try to find heading from custom property (getting the name from the alias) @@ -77,7 +79,7 @@ namespace Umbraco.Web.Editors if (property != null) { column.Header = property.Name; - column.LocalizationKey = string.Empty; + column.AllowSorting = false; // can't sort on custom property columns } else if (alias == "UpdateDate") { diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs index 70184d6d32..3c34c0c7fa 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeContainerConfiguration.cs @@ -70,6 +70,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "localizationKey")] public string LocalizationKey { get; set; } + + [DataMember(Name = "allowSorting")] + public bool AllowSorting { get; set; } } } } From 9a0451e1ad80bed64f4852a13e2f8f2fc2187b7b Mon Sep 17 00:00:00 2001 From: AndyButland Date: Wed, 30 Jul 2014 09:43:37 +0200 Subject: [PATCH 14/18] Improvements to UI for selecting additional columns for container list view --- .../listview/listview.controller.js | 2 +- .../controls/ContentTypeControlNew.ascx | 175 ++++++++++++++++-- .../ContentTypeControlNew.ascx.designer.cs | 1 + .../ContentAndMediaTypeBaseController.cs | 10 +- .../controls/ContentTypeControlNew.ascx.cs | 70 +++++-- 5 files changed, 229 insertions(+), 29 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 7cc4643aa4..aac3e436af 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 @@ -41,7 +41,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific allowBulkDelete: true, additionalColumns: [ { alias: 'UpdateDate', header: 'Last edited', localizationKey: 'defaultdialogs_lastEdited' }, - { alias: 'Owner', header: 'Last edited', localizationKey: 'content_updatedBy' } + { alias: 'Updator', header: 'Last edited', localizationKey: 'content_updatedBy' } ] }; diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index 1c1e4cc625..4e3e26bd6c 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -76,51 +76,200 @@
+ + + + +
-
- +
+ - + + + + + + + + + + + + +
Selected columns
- - + + - + - Ascending Descending - + - Yes No - + - Yes No - + - Yes No diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs index 582c67837d..deda04c7b6 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs @@ -11,5 +11,6 @@ namespace Umbraco.Web.UI.Umbraco.Controls { public partial class ContentTypeControlNew { + } } diff --git a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs index c289b80888..8a57ce921d 100644 --- a/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs +++ b/src/Umbraco.Web/Editors/ContentAndMediaTypeBaseController.cs @@ -87,15 +87,21 @@ namespace Umbraco.Web.Editors column.Header = "Last edited"; column.LocalizationKey = "defaultdialogs_lastEdited"; } - else if (alias == "Owner") + else if (alias == "Updator") { // Special case to restore hard-coded column titles (2) column.Header = "Updated by"; column.LocalizationKey = "content_updatedBy"; } + else if (alias == "Owner") + { + // Special case to restore hard-coded column titles (3) + column.Header = "Created by"; + column.LocalizationKey = "content_createBy"; + } else { - // Otherwise just sentence case the alias + // For others just sentence case the alias and camel case for the key column.Header = alias.ToFirstUpper().SplitPascalCasing(); column.LocalizationKey = "content_" + alias.ToFirstLower(); } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 3156cf5cdb..60223b37ef 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -293,7 +293,14 @@ namespace umbraco.controls //_contentType.ContentTypeItem.Thumbnail = ddlThumbnails.SelectedValue; _contentType.ContentTypeItem.AllowedAsRoot = allowAtRoot.Checked; _contentType.ContentTypeItem.IsContainer = cb_isContainer.Checked; - _contentType.ContentTypeItem.ContainerConfig = GetProvidedContainerConfigAsJsonString(); + if (cb_isContainer.Checked) + { + _contentType.ContentTypeItem.ContainerConfig = GetProvidedContainerConfigAsJsonString(); + } + else + { + _contentType.ContentTypeItem.ContainerConfig = string.Empty; + } int i = 0; var ids = SaveAllowedChildTypes(); @@ -367,9 +374,9 @@ namespace umbraco.controls // Set defaults for saving if not all fields are provided var pageSize = 10; - var additionalColumns = "UpdateDate,Owner"; - var orderBy = "UpdateDate"; - var orderDirection = "desc"; + var additionalColumns = string.Empty; + var orderBy = "Name"; + var orderDirection = "asc"; var allowBulkPublish = true; var allowBulkUnpublish = true; var allowBulkDelete = true; @@ -384,9 +391,9 @@ namespace umbraco.controls configProvided = true; } - if (!string.IsNullOrEmpty(txtContainerConfigOrderBy.Text)) + if (ddlContainerConfigOrderBy.SelectedIndex > 0) { - orderBy = txtContainerConfigOrderBy.Text; + orderBy = ddlContainerConfigOrderBy.SelectedItem.Value; configProvided = true; } @@ -645,27 +652,63 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); DualAllowedContentTypes.Value = chosenContentTypeIDs; } + // Set up options for columns and order by + ddlContainerConfigOrderBy.Items.Add(new ListItem(string.Empty, string.Empty)); + ddlContainerConfigOrderBy.Items.Add(new ListItem("Node name", "Name")); + ddlContainerConfigOrderBy.Items.Add(new ListItem("Last edited on", "UpdateDate")); + ddlContainerConfigOrderBy.Items.Add(new ListItem("Last updated by", "Updator")); + ddlContainerConfigOrderBy.Items.Add(new ListItem("Created on", "CreateDate")); + ddlContainerConfigOrderBy.Items.Add(new ListItem("Created by", "Owner")); + + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem("Select a column...", string.Empty)); + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem("Node name", "Name")); + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem("Last edited on", "UpdateDate")); + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem("Last updated by", "Updator")); + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem("Created on", "CreateDate")); + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem("Created by", "Owner")); + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem("---", string.Empty)); + + // - get properties from allowed document types (i.e. those that might appear in the list view) + var allPropertiesOfAllowedContentTypes = Services.ContentTypeService + .GetAllContentTypes(_contentType.AllowedChildContentTypeIDs) + .SelectMany(x => x.PropertyTypes) + .ToList(); + foreach (var property in allPropertiesOfAllowedContentTypes) + { + ddlContainerConfigAdditionalColumnsChooser.Items.Add(new ListItem(property.Name, property.Alias)); + } + + // Populate controls with values allowAtRoot.Checked = _contentType.AllowAtRoot; cb_isContainer.Checked = _contentType.IsContainerContentType; + ddlContainerConfigOrderBy.SelectedIndex = -1; ddlContainerConfigOrderDirection.SelectedIndex = -1; ddlContainerConfigAllowBulkPublish.SelectedIndex = -1; ddlContainerConfigAllowBulkUnpublish.SelectedIndex = -1; ddlContainerConfigAllowBulkDelete.SelectedIndex = -1; - if (!string.IsNullOrEmpty(_contentType.ContainerConfig)) + + if (_contentType.IsContainerContentType && !string.IsNullOrEmpty(_contentType.ContainerConfig)) { var containerConfig = GetContentTypeContainerConfigurationFromJsonString(_contentType.ContainerConfig); txtContainerConfigPageSize.Text = containerConfig.PageSize.ToString(); txtContainerConfigAdditionalColumns.Text = containerConfig.AdditionalColumnAliases; - txtContainerConfigOrderBy.Text = containerConfig.OrderBy; + ddlContainerConfigOrderBy.Items.FindByValue(containerConfig.OrderBy).Selected = true; ddlContainerConfigOrderDirection.Items.FindByValue(containerConfig.OrderDirection).Selected = true; - ddlContainerConfigAllowBulkPublish.SelectedIndex = containerConfig.AllowBulkPublish ? 1 : 2; - ddlContainerConfigAllowBulkUnpublish.SelectedIndex = containerConfig.AllowBulkUnpublish ? 1 : 2; - ddlContainerConfigAllowBulkDelete.SelectedIndex = containerConfig.AllowBulkDelete ? 1 : 2; + ddlContainerConfigAllowBulkPublish.SelectedIndex = containerConfig.AllowBulkPublish ? 0 : 1; + ddlContainerConfigAllowBulkUnpublish.SelectedIndex = containerConfig.AllowBulkUnpublish ? 0 : 1; + ddlContainerConfigAllowBulkDelete.SelectedIndex = containerConfig.AllowBulkDelete ? 0 : 1; } else { - txtContainerConfigPageSize.Text = string.Empty; + // Set defaults matching original hard-coded values unless config has been provided + txtContainerConfigPageSize.Text = "10"; + txtContainerConfigAdditionalColumns.Text = "UpdateDate,Updator"; + ddlContainerConfigOrderBy.Items.FindByValue("UpdateDate").Selected = true; + ddlContainerConfigOrderDirection.Items.FindByValue("desc").Selected = true; + ddlContainerConfigAllowBulkPublish.SelectedIndex = 0; + ddlContainerConfigAllowBulkUnpublish.SelectedIndex = 0; + ddlContainerConfigAllowBulkDelete.SelectedIndex = 0; } } @@ -1445,10 +1488,11 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected global::System.Web.UI.WebControls.TextBox txtContainerConfigPageSize; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigAdditionalColumns; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigAdditionalColumnsChooser; protected global::System.Web.UI.WebControls.TextBox txtContainerConfigAdditionalColumns; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderBy; - protected global::System.Web.UI.WebControls.TextBox txtContainerConfigOrderBy; + protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderBy; protected global::umbraco.uicontrols.PropertyPanel pp_containerConfigOrderDirection; protected global::System.Web.UI.WebControls.DropDownList ddlContainerConfigOrderDirection; From 45c344a0cae4a9c4e72bdec532f690048564d086 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Wed, 30 Jul 2014 22:05:43 +0200 Subject: [PATCH 15/18] Localisation of container config fields; applied sortable to list of additional columns --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 7 ++ .../umbraco/config/lang/en_us.xml | 7 ++ .../controls/ContentTypeControlNew.ascx | 76 ++++++++++++------- .../controls/ContentTypeControlNew.ascx.cs | 8 ++ 4 files changed, 69 insertions(+), 29 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 16b943481b..34188fda01 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -252,6 +252,13 @@ Tab Thumbnail Enable list view + Number of entries per page when selected for display in list view.]]> + Select the additional columns displayed after the node name.]]> + The default order for the list.]]> + The direction of the default order for the list.]]> + Indicates if bulk publishing is allowed when defined as a list view]]> + Indicates if bulk unpublishing is allowed when defined as a list view]]> + Indicates if bulk deletion is allowed when defined as a list view]]> Add prevalue diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index ad78006b03..7c727db3b8 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -258,6 +258,13 @@ Tab Thumbnail Enable list view + Number of entries per page when selected for display in list view.]]> + Select the additional columns displayed after the node name.]]> + The default order for the list.]]> + The direction of the default order for the list.]]> + Indicates if bulk publishing is allowed when defined as a list view]]> + Indicates if bulk unpublishing is allowed when defined as a list view]]> + Indicates if bulk deletion is allowed when defined as a list view]]> Add prevalue diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index 4e3e26bd6c..a2602b520a 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -77,22 +77,27 @@
+ +
+
+ - -
-
-
- +
+ - + - - + @@ -243,32 +261,32 @@ - + - + Ascending Descending - + Yes No - + Yes No - + Yes No diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 60223b37ef..8012606a99 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -103,6 +103,14 @@ namespace umbraco.controls pp_icon.Text = ui.Text("icon", Security.CurrentUser); pp_isContainer.Text = ui.Text("editcontenttype", "hasListView", Security.CurrentUser); + + pp_containerConfigPageSize.Text = ui.Text("editcontenttype", "containerConfigPageSize", Security.CurrentUser); + pp_containerConfigAdditionalColumns.Text = ui.Text("editcontenttype", "containerConfigAdditionalColumns", Security.CurrentUser); + pp_containerConfigOrderBy.Text = ui.Text("editcontenttype", "containerConfigOrderBy", Security.CurrentUser); + pp_containerConfigOrderDirection.Text = ui.Text("editcontenttype", "containerConfigOrderDirection", Security.CurrentUser); + pp_allowBulkPublish.Text = ui.Text("editcontenttype", "allowBulkPublish", Security.CurrentUser); + pp_allowBulkUnpublish.Text = ui.Text("editcontenttype", "allowBulkUnpublish", Security.CurrentUser); + pp_allowBulkDelete.Text = ui.Text("editcontenttype", "allowBulkDelete", Security.CurrentUser); // we'll disable this... if (!Page.IsPostBack && _contentType.MasterContentType != 0) From 964e18b84fa7971811af185b0f661957fb5517e5 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Wed, 30 Jul 2014 23:14:24 +0200 Subject: [PATCH 16/18] Set up return to list button for list view children that on click returns to the list with the last viewed page restored --- .../views/content/content.edit.controller.js | 14 ++- .../src/views/content/edit.html | 9 +- .../listview/listview.controller.js | 20 +++- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 1 + .../umbraco/config/lang/en_us.xml | 1 + .../controls/ContentTypeControlNew.ascx | 2 +- .../ContentEditing/ContentItemDisplayBase.cs | 6 ++ .../Models/Mapping/ContentModelMapper.cs | 3 + .../controls/ContentTypeControlNew.ascx.cs | 95 +++++-------------- 9 files changed, 75 insertions(+), 76 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js index 90b1b513a3..7003941916 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js @@ -6,7 +6,7 @@ * @description * The controller for the content editor */ -function ContentEditController($scope, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, keyboardService, umbModelMapper, editorState, $http) { +function ContentEditController($scope, $rootScope, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, keyboardService, umbModelMapper, editorState, $http) { //setup scope vars $scope.defaultButton = null; @@ -188,6 +188,15 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS return deferred.promise; } + function resetLastListPageNumber(content) { + // We're using rootScope to store the page number for list views, so if returning to the list + // we can restore the page. If we've moved on to edit a piece of content that's not the list or it's children + // we should remove this so as not to confuse if navigating to a different list + if (!content.isChildOfListView && !content.isContainer) { + $rootScope.lastPageNumber = null; + } + } + if ($routeParams.create) { //we are creating so get an empty content item contentResource.getScaffold($routeParams.id, $routeParams.doctype) @@ -198,6 +207,8 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS editorState.set($scope.content); configureButtons($scope.content); + + resetLastListPageNumber($scope.content); }); } else { @@ -219,6 +230,7 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS syncTreeNode($scope.content, data.path, true); + resetLastListPageNumber($scope.content); }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/content/edit.html index e3c079231a..b2b24585d5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/edit.html @@ -45,6 +45,12 @@ + +
@@ -54,8 +60,9 @@ - + Return to list +
-
Selected columnsSelected columns
+