269 lines
12 KiB
C#
269 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using AutoMapper;
|
|
using Umbraco.Core;
|
|
using Umbraco.Core.Models;
|
|
using Umbraco.Core.PropertyEditors;
|
|
using Umbraco.Core.Services;
|
|
using Umbraco.Web.Models.ContentEditing;
|
|
using umbraco;
|
|
|
|
namespace Umbraco.Web.Models.Mapping
|
|
{
|
|
/// <summary>
|
|
/// Creates the tabs collection with properties assigned for display models
|
|
/// </summary>
|
|
internal class TabsAndPropertiesResolver : ValueResolver<IContentBase, IEnumerable<Tab<ContentPropertyDisplay>>>
|
|
{
|
|
private readonly ILocalizedTextService _localizedTextService;
|
|
protected IEnumerable<string> IgnoreProperties { get; set; }
|
|
|
|
public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService)
|
|
{
|
|
if (localizedTextService == null) throw new ArgumentNullException("localizedTextService");
|
|
_localizedTextService = localizedTextService;
|
|
IgnoreProperties = new List<string>();
|
|
}
|
|
|
|
public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService, IEnumerable<string> ignoreProperties)
|
|
: this(localizedTextService)
|
|
{
|
|
if (ignoreProperties == null) throw new ArgumentNullException("ignoreProperties");
|
|
IgnoreProperties = ignoreProperties;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps properties on to the generic properties tab
|
|
/// </summary>
|
|
/// <param name="content"></param>
|
|
/// <param name="display"></param>
|
|
/// <param name="localizedTextService"></param>
|
|
/// <param name="customProperties">
|
|
/// Any additional custom properties to assign to the generic properties tab.
|
|
/// </param>
|
|
/// <param name="onGenericPropertiesMapped"></param>
|
|
/// <remarks>
|
|
/// The generic properties tab is mapped during AfterMap and is responsible for
|
|
/// setting up the properties such as Created date, updated date, template selected, etc...
|
|
/// </remarks>
|
|
public static void MapGenericProperties<TPersisted>(
|
|
TPersisted content,
|
|
ContentItemDisplayBase<ContentPropertyDisplay, TPersisted> display,
|
|
ILocalizedTextService localizedTextService,
|
|
IEnumerable<ContentPropertyDisplay> customProperties = null,
|
|
Action<List<ContentPropertyDisplay>> onGenericPropertiesMapped = null)
|
|
where TPersisted : IContentBase
|
|
{
|
|
var genericProps = display.Tabs.Single(x => x.Id == 0);
|
|
|
|
//store the current props to append to the newly inserted ones
|
|
var currProps = genericProps.Properties.ToArray();
|
|
|
|
var labelEditor = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View;
|
|
|
|
var contentProps = new List<ContentPropertyDisplay>
|
|
{
|
|
new ContentPropertyDisplay
|
|
{
|
|
Alias = string.Format("{0}id", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
|
Label = "Id",
|
|
Value = Convert.ToInt32(display.Id).ToInvariantString() + "<br/><small class='muted'>" + display.Key + "</small>",
|
|
View = labelEditor
|
|
},
|
|
new ContentPropertyDisplay
|
|
{
|
|
Alias = string.Format("{0}creator", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
|
Label = localizedTextService.Localize("content/createBy"),
|
|
Description = localizedTextService.Localize("content/createByDesc"),
|
|
Value = display.Owner.Name,
|
|
View = labelEditor
|
|
},
|
|
new ContentPropertyDisplay
|
|
{
|
|
Alias = string.Format("{0}createdate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
|
Label = localizedTextService.Localize("content/createDate"),
|
|
Description = localizedTextService.Localize("content/createDateDesc"),
|
|
Value = display.CreateDate.ToIsoString(),
|
|
View = labelEditor
|
|
},
|
|
new ContentPropertyDisplay
|
|
{
|
|
Alias = string.Format("{0}updatedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
|
Label = localizedTextService.Localize("content/updateDate"),
|
|
Description = localizedTextService.Localize("content/updateDateDesc"),
|
|
Value = display.UpdateDate.ToIsoString(),
|
|
View = labelEditor
|
|
}
|
|
};
|
|
|
|
if (customProperties != null)
|
|
{
|
|
//add the custom ones
|
|
contentProps.AddRange(customProperties);
|
|
}
|
|
|
|
//now add the user props
|
|
contentProps.AddRange(currProps);
|
|
|
|
//callback
|
|
if (onGenericPropertiesMapped != null)
|
|
{
|
|
onGenericPropertiesMapped(contentProps);
|
|
}
|
|
|
|
//re-assign
|
|
genericProps.Properties = contentProps;
|
|
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the container (listview) tab to the document
|
|
/// </summary>
|
|
/// <typeparam name="TPersisted"></typeparam>
|
|
/// <param name="display"></param>
|
|
/// <param name="entityType">This must be either 'content' or 'media'</param>
|
|
/// <param name="dataTypeService"></param>
|
|
internal static void AddListView<TPersisted>(TabbedContentItem<ContentPropertyDisplay, TPersisted> display, string entityType, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService)
|
|
where TPersisted : IContentBase
|
|
{
|
|
int dtdId;
|
|
var customDtdName = Constants.Conventions.DataTypes.ListViewPrefix + display.ContentTypeAlias;
|
|
switch (entityType)
|
|
{
|
|
case "content":
|
|
dtdId = Constants.System.DefaultContentListViewDataTypeId;
|
|
|
|
break;
|
|
case "media":
|
|
dtdId = Constants.System.DefaultMediaListViewDataTypeId;
|
|
break;
|
|
case "member":
|
|
dtdId = Constants.System.DefaultMembersListViewDataTypeId;
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException("entityType does not match a required value");
|
|
}
|
|
|
|
//first try to get the custom one if there is one
|
|
var dt = dataTypeService.GetDataTypeDefinitionByName(customDtdName)
|
|
?? dataTypeService.GetDataTypeDefinitionById(dtdId);
|
|
|
|
if (dt == null)
|
|
{
|
|
throw new InvalidOperationException("No list view data type was found for this document type, ensure that the default list view data types exists and/or that your custom list view data type exists");
|
|
}
|
|
|
|
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(dt.Id);
|
|
|
|
var editor = PropertyEditorResolver.Current.GetByAlias(dt.PropertyEditorAlias);
|
|
if (editor == null)
|
|
{
|
|
throw new NullReferenceException("The property editor with alias " + dt.PropertyEditorAlias + " does not exist");
|
|
}
|
|
|
|
var listViewTab = new Tab<ContentPropertyDisplay>();
|
|
listViewTab.Alias = Constants.Conventions.PropertyGroups.ListViewGroupName;
|
|
listViewTab.Label = localizedTextService.Localize("content/childItems");
|
|
listViewTab.Id = 25;
|
|
listViewTab.IsActive = true;
|
|
|
|
var listViewConfig = editor.PreValueEditor.ConvertDbToEditor(editor.DefaultPreValues, preVals);
|
|
//add the entity type to the config
|
|
listViewConfig["entityType"] = entityType;
|
|
|
|
var listViewProperties = new List<ContentPropertyDisplay>();
|
|
listViewProperties.Add(new ContentPropertyDisplay
|
|
{
|
|
Alias = string.Format("{0}containerView", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
|
Label = "",
|
|
Value = null,
|
|
View = editor.ValueEditor.View,
|
|
HideLabel = true,
|
|
Config = listViewConfig
|
|
});
|
|
listViewTab.Properties = listViewProperties;
|
|
|
|
//Is there a better way?
|
|
var tabs = new List<Tab<ContentPropertyDisplay>>();
|
|
tabs.Add(listViewTab);
|
|
tabs.AddRange(display.Tabs);
|
|
display.Tabs = tabs;
|
|
|
|
}
|
|
|
|
protected override IEnumerable<Tab<ContentPropertyDisplay>> ResolveCore(IContentBase content)
|
|
{
|
|
var aggregateTabs = new List<Tab<ContentPropertyDisplay>>();
|
|
|
|
//now we need to aggregate the tabs and properties since we might have duplicate tabs (based on aliases) because
|
|
// of how content composition works.
|
|
foreach (var propertyGroups in content.PropertyGroups.OrderBy(x => x.SortOrder).GroupBy(x => x.Name))
|
|
{
|
|
var aggregateProperties = new List<ContentPropertyDisplay>();
|
|
|
|
//add the properties from each composite property group
|
|
foreach (var current in propertyGroups)
|
|
{
|
|
var propsForGroup = content.GetPropertiesForGroup(current)
|
|
.Where(x => IgnoreProperties.Contains(x.Alias) == false); //don't include ignored props
|
|
|
|
aggregateProperties.AddRange(
|
|
Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(
|
|
propsForGroup));
|
|
}
|
|
|
|
if (aggregateProperties.Count == 0)
|
|
continue;
|
|
|
|
TranslateProperties(aggregateProperties);
|
|
|
|
//then we'll just use the root group's data to make the composite tab
|
|
var rootGroup = propertyGroups.First(x => x.ParentId == null);
|
|
|
|
aggregateTabs.Add(new Tab<ContentPropertyDisplay>
|
|
{
|
|
Id = rootGroup.Id,
|
|
Alias = rootGroup.Name,
|
|
Label = _localizedTextService.UmbracoDictionaryTranslate(rootGroup.Name),
|
|
Properties = aggregateProperties,
|
|
IsActive = false
|
|
});
|
|
}
|
|
|
|
//now add the generic properties tab for any properties that don't belong to a tab
|
|
var orphanProperties = content.GetNonGroupedProperties()
|
|
.Where(x => IgnoreProperties.Contains(x.Alias) == false); //don't include ignored props
|
|
|
|
//now add the generic properties tab
|
|
var genericproperties = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(orphanProperties).ToList();
|
|
TranslateProperties(genericproperties);
|
|
|
|
aggregateTabs.Add(new Tab<ContentPropertyDisplay>
|
|
{
|
|
Id = 0,
|
|
Label = _localizedTextService.Localize("general/properties"),
|
|
Alias = "Generic properties",
|
|
Properties = genericproperties
|
|
});
|
|
|
|
//set the first tab to active
|
|
aggregateTabs.First().IsActive = true;
|
|
|
|
return aggregateTabs;
|
|
}
|
|
|
|
private void TranslateProperties(IEnumerable<ContentPropertyDisplay> properties)
|
|
{
|
|
// Not sure whether it's a good idea to add this to the ContentPropertyDisplay mapper
|
|
foreach (var prop in properties)
|
|
{
|
|
prop.Label = _localizedTextService.UmbracoDictionaryTranslate(prop.Label);
|
|
prop.Description = _localizedTextService.UmbracoDictionaryTranslate(prop.Description);
|
|
}
|
|
}
|
|
}
|
|
}
|