Created new field in cmsContentType and related models for storing the configuration for a container doc type; implemented configurable page size
This commit is contained in:
@@ -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<ContentTypeBase, int>(x => x.CreatorId);
|
||||
private static readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.AllowedAsRoot);
|
||||
private static readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.IsContainer);
|
||||
private static readonly PropertyInfo ContainerConfigSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.ContainerConfig);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
|
||||
private static readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
@@ -303,6 +305,23 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets a JSON string defining the configuration for this ContentType if set as a container
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual string ContainerConfig
|
||||
{
|
||||
get { return _containerConfig; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_containerConfig = value;
|
||||
return _containerConfig;
|
||||
}, _containerConfig, ContainerConfigSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this ContentType is Trashed or not.
|
||||
/// If ContentType is Trashed it will be located in the Recyclebin.
|
||||
|
||||
@@ -43,6 +43,11 @@ namespace Umbraco.Core.Models
|
||||
/// </remarks>
|
||||
bool IsContainer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets a JSON string defining the configuration for this ContentType if set as a container
|
||||
/// </summary>
|
||||
string ContainerConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets a list of integer Ids of the ContentTypes allowed under the ContentType
|
||||
/// </summary>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.Description, dto => dto.Description);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.ContainerConfig, dto => dto.ContainerConfig);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.Description, dto => dto.Description);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.ContainerConfig, dto => dto.ContainerConfig);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.Description, dto => dto.Description);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.ContainerConfig, dto => dto.ContainerConfig);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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
|
||||
* <pre>
|
||||
* contentTypeResource.getContainerConfig(1234)
|
||||
* .then(function(config) {
|
||||
* $scope.options = {
|
||||
* pageSize: config.pageSize,
|
||||
* };
|
||||
* });
|
||||
* </pre>
|
||||
* @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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -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
|
||||
* <pre>
|
||||
* mediaTypeResource.getContainerConfig(1234)
|
||||
* .then(function(config) {
|
||||
* $scope.options = {
|
||||
* pageSize: config.pageSize,
|
||||
* };
|
||||
* });
|
||||
* </pre>
|
||||
* @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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the container configuration JSON structure for the content item id passed in
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
public ContentTypeContainerConfiguration GetContainerConfig(int contentId)
|
||||
{
|
||||
var contentItem = Services.ContentService.GetById(contentId);
|
||||
if (contentItem == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<ContentTypeContainerConfiguration>(contentItem.ContentType.ContainerConfig);
|
||||
}
|
||||
|
||||
// TODO: This should really be centralized and used anywhere globalization applies.
|
||||
internal string TranslateItem(string text)
|
||||
{
|
||||
|
||||
@@ -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<IMediaType, ContentTypeBasic>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the container configuration JSON structure for the content item id passed in
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
public JsonNetResult GetContainerConfig(int contentId)
|
||||
{
|
||||
var contentItem = Services.ContentService.GetById(contentId);
|
||||
if (contentItem == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<ContentTypeContainerConfiguration>(contentItem.ContentType.ContainerConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
/// <summary>
|
||||
/// A model representing the configuration for a content type defined as a list container
|
||||
/// </summary>
|
||||
[DataContract(Name = "config", Namespace = "")]
|
||||
public class ContentTypeContainerConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// The page size for the list
|
||||
/// </summary>
|
||||
[DataMember(Name = "pageSize", IsRequired = true)]
|
||||
[Required]
|
||||
public int PageSize { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -300,6 +300,7 @@
|
||||
<Compile Include="Editors\EntityControllerConfigurationAttribute.cs" />
|
||||
<Compile Include="Editors\ImagesController.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentBaseItemSave.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentTypeContainerConfiguration.cs" />
|
||||
<Compile Include="Models\ContentEditing\MediaItemSave.cs" />
|
||||
<Compile Include="Models\DetachedContent.cs" />
|
||||
<Compile Include="Models\ImageCropAnchor.cs" />
|
||||
|
||||
Reference in New Issue
Block a user