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/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/content/content.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js index 90b1b513a3..cca8fc65c6 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.lastListViewPageViewed = 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 +
-
+ -
+ -
+
Delete @@ -45,16 +45,23 @@ - - - Name - - - Last edited - - - Updated by - + + + + + Name + + + + + + + {{getColumnName($index)}} + {{getColumnName($index)}} + + + +
@@ -78,27 +85,23 @@ - {{result.name}} - - {{result.updateDate|date:'medium'}} - - - - {{result.owner.name}} - + + + {{getPropertyValue(column.alias, result)}} + - +