2013-09-02 15:40:14 +02:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using AutoMapper ;
using Umbraco.Core ;
using Umbraco.Core.Models ;
using Umbraco.Core.PropertyEditors ;
2014-09-18 11:52:12 +10:00
using Umbraco.Core.Services ;
2013-09-02 15:40:14 +02:00
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 > > >
2016-01-06 11:22:15 +01:00
{
private readonly ILocalizedTextService _localizedTextService ;
2013-10-22 17:36:46 +11:00
protected IEnumerable < string > IgnoreProperties { get ; set ; }
2013-09-30 15:42:29 +10:00
2016-01-06 11:22:15 +01:00
public TabsAndPropertiesResolver ( ILocalizedTextService localizedTextService )
2013-09-30 15:42:29 +10:00
{
2016-01-06 11:22:15 +01:00
if ( localizedTextService = = null ) throw new ArgumentNullException ( "localizedTextService" ) ;
_localizedTextService = localizedTextService ;
2013-10-22 17:36:46 +11:00
IgnoreProperties = new List < string > ( ) ;
2013-09-30 15:42:29 +10:00
}
2016-01-06 11:22:15 +01:00
public TabsAndPropertiesResolver ( ILocalizedTextService localizedTextService , IEnumerable < string > ignoreProperties )
: this ( localizedTextService )
2015-10-28 12:28:29 +01:00
{
2013-09-30 15:42:29 +10:00
if ( ignoreProperties = = null ) throw new ArgumentNullException ( "ignoreProperties" ) ;
2013-10-22 17:36:46 +11:00
IgnoreProperties = ignoreProperties ;
2013-09-30 15:42:29 +10:00
}
2013-09-02 15:40:14 +02:00
/// <summary>
/// Maps properties on to the generic properties tab
/// </summary>
/// <param name="content"></param>
/// <param name="display"></param>
2016-01-06 11:22:15 +01:00
/// <param name="localizedTextService"></param>
2013-09-02 15:40:14 +02:00
/// <param name="customProperties">
/// Any additional custom properties to assign to the generic properties tab.
/// </param>
2015-10-28 12:28:29 +01:00
/// <param name="onGenericPropertiesMapped"></param>
2013-09-02 15:40:14 +02:00
/// <remarks>
/// The generic properties tab is mapped during AfterMap and is responsible for
2014-09-15 13:53:33 +10:00
/// setting up the properties such as Created date, updated date, template selected, etc...
2013-09-02 15:40:14 +02:00
/// </remarks>
public static void MapGenericProperties < TPersisted > (
2013-10-09 15:07:09 +02:00
TPersisted content ,
2013-09-02 15:40:14 +02:00
ContentItemDisplayBase < ContentPropertyDisplay , TPersisted > display ,
2016-01-06 11:22:15 +01:00
ILocalizedTextService localizedTextService ,
2015-10-28 12:28:29 +01:00
IEnumerable < ContentPropertyDisplay > customProperties = null ,
Action < List < ContentPropertyDisplay > > onGenericPropertiesMapped = null )
2013-09-02 15:40:14 +02:00
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 ( ) ;
2013-09-06 15:27:38 +10:00
var labelEditor = PropertyEditorResolver . Current . GetByAlias ( Constants . PropertyEditors . NoEditAlias ) . ValueEditor . View ;
2013-09-02 15:40:14 +02:00
var contentProps = new List < ContentPropertyDisplay >
2015-10-28 12:28:29 +01:00
{
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 ) ,
2016-01-06 11:22:15 +01:00
Label = localizedTextService . Localize ( "content/createBy" ) ,
Description = localizedTextService . Localize ( "content/createByDesc" ) ,
2015-10-28 12:28:29 +01:00
Value = display . Owner . Name ,
View = labelEditor
} ,
new ContentPropertyDisplay
2013-09-02 15:40:14 +02:00
{
2015-10-28 12:28:29 +01:00
Alias = string . Format ( "{0}createdate" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
2016-01-06 11:22:15 +01:00
Label = localizedTextService . Localize ( "content/createDate" ) ,
Description = localizedTextService . Localize ( "content/createDateDesc" ) ,
2015-10-28 12:28:29 +01:00
Value = display . CreateDate . ToIsoString ( ) ,
View = labelEditor
} ,
new ContentPropertyDisplay
{
Alias = string . Format ( "{0}updatedate" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
2016-01-06 11:22:15 +01:00
Label = localizedTextService . Localize ( "content/updateDate" ) ,
Description = localizedTextService . Localize ( "content/updateDateDesc" ) ,
2015-10-28 12:28:29 +01:00
Value = display . UpdateDate . ToIsoString ( ) ,
View = labelEditor
}
} ;
2013-09-02 15:40:14 +02:00
2015-10-28 12:28:29 +01:00
if ( customProperties ! = null )
{
//add the custom ones
contentProps . AddRange ( customProperties ) ;
}
2013-09-02 15:40:14 +02:00
//now add the user props
contentProps . AddRange ( currProps ) ;
2015-10-28 12:28:29 +01:00
//callback
if ( onGenericPropertiesMapped ! = null )
{
onGenericPropertiesMapped ( contentProps ) ;
}
2013-09-02 15:40:14 +02:00
//re-assign
genericProps . Properties = contentProps ;
2013-10-09 15:07:09 +02:00
2015-10-28 12:28:29 +01:00
2013-09-02 15:40:14 +02:00
}
2013-11-15 16:56:51 +11:00
/// <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>
2014-09-22 18:18:09 +10:00
/// <param name="dataTypeService"></param>
2016-01-06 11:22:15 +01:00
internal static void AddListView < TPersisted > ( TabbedContentItem < ContentPropertyDisplay , TPersisted > display , string entityType , IDataTypeService dataTypeService , ILocalizedTextService localizedTextService )
2013-10-20 23:36:26 +02:00
where TPersisted : IContentBase
{
2014-09-18 11:52:12 +10:00
int dtdId ;
2014-09-22 18:18:09 +10:00
var customDtdName = Constants . Conventions . DataTypes . ListViewPrefix + display . ContentTypeAlias ;
2014-09-18 11:52:12 +10:00
switch ( entityType )
{
case "content" :
dtdId = Constants . System . DefaultContentListViewDataTypeId ;
2014-09-22 18:18:09 +10:00
2014-09-18 11:52:12 +10:00
break ;
case "media" :
dtdId = Constants . System . DefaultMediaListViewDataTypeId ;
break ;
2014-09-19 09:47:42 +10:00
case "member" :
2014-09-18 11:52:12 +10:00
dtdId = Constants . System . DefaultMembersListViewDataTypeId ;
break ;
default :
throw new ArgumentOutOfRangeException ( "entityType does not match a required value" ) ;
}
2014-09-22 18:18:09 +10:00
//first try to get the custom one if there is one
var dt = dataTypeService . GetDataTypeDefinitionByName ( customDtdName )
? ? dataTypeService . GetDataTypeDefinitionById ( dtdId ) ;
2015-01-30 10:18:19 +11:00
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" ) ;
}
2014-09-22 18:18:09 +10:00
var preVals = dataTypeService . GetPreValuesCollectionByDataTypeId ( dt . Id ) ;
2014-09-18 11:52:12 +10:00
var editor = PropertyEditorResolver . Current . GetByAlias ( dt . PropertyEditorAlias ) ;
if ( editor = = null )
{
throw new NullReferenceException ( "The property editor with alias " + dt . PropertyEditorAlias + " does not exist" ) ;
}
2014-09-15 13:53:33 +10:00
2014-09-18 09:48:08 +10:00
var listViewTab = new Tab < ContentPropertyDisplay > ( ) ;
listViewTab . Alias = Constants . Conventions . PropertyGroups . ListViewGroupName ;
2016-01-06 11:22:15 +01:00
listViewTab . Label = localizedTextService . Localize ( "content/childItems" ) ;
2014-09-18 09:48:08 +10:00
listViewTab . Id = 25 ;
listViewTab . IsActive = true ;
2014-09-18 11:52:12 +10:00
var listViewConfig = editor . PreValueEditor . ConvertDbToEditor ( editor . DefaultPreValues , preVals ) ;
//add the entity type to the config
listViewConfig [ "entityType" ] = entityType ;
2014-09-18 09:48:08 +10:00
var listViewProperties = new List < ContentPropertyDisplay > ( ) ;
listViewProperties . Add ( new ContentPropertyDisplay
2013-10-20 23:36:26 +02:00
{
2014-09-18 09:48:08 +10:00
Alias = string . Format ( "{0}containerView" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
Label = "" ,
Value = null ,
2014-09-18 11:52:12 +10:00
View = editor . ValueEditor . View ,
2014-09-18 09:48:08 +10:00
HideLabel = true ,
2014-09-18 11:52:12 +10:00
Config = listViewConfig
2014-09-18 09:48:08 +10:00
} ) ;
listViewTab . Properties = listViewProperties ;
//Is there a better way?
var tabs = new List < Tab < ContentPropertyDisplay > > ( ) ;
tabs . Add ( listViewTab ) ;
tabs . AddRange ( display . Tabs ) ;
display . Tabs = tabs ;
2014-09-15 13:53:33 +10:00
2013-10-20 23:36:26 +02:00
}
2013-09-02 15:40:14 +02:00
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.
2013-09-30 13:18:34 +02:00
foreach ( var propertyGroups in content . PropertyGroups . OrderBy ( x = > x . SortOrder ) . GroupBy ( x = > x . Name ) )
2013-09-02 15:40:14 +02:00
{
var aggregateProperties = new List < ContentPropertyDisplay > ( ) ;
2013-12-05 18:33:51 +11:00
//add the properties from each composite property group
foreach ( var current in propertyGroups )
2013-09-02 15:40:14 +02:00
{
2013-09-30 15:42:29 +10:00
var propsForGroup = content . GetPropertiesForGroup ( current )
2013-10-22 17:36:46 +11:00
. Where ( x = > IgnoreProperties . Contains ( x . Alias ) = = false ) ; //don't include ignored props
2013-09-30 15:42:29 +10:00
2013-09-02 15:40:14 +02:00
aggregateProperties . AddRange (
Mapper . Map < IEnumerable < Property > , IEnumerable < ContentPropertyDisplay > > (
2013-09-30 15:42:29 +10:00
propsForGroup ) ) ;
2013-09-02 15:40:14 +02:00
}
2013-12-05 18:33:51 +11:00
2014-11-18 10:29:46 +01:00
if ( aggregateProperties . Count = = 0 )
continue ;
2014-11-21 09:25:57 +11:00
TranslateProperties ( aggregateProperties ) ;
2014-11-20 15:19:58 +00:00
2013-09-02 15:40:14 +02:00
//then we'll just use the root group's data to make the composite tab
2014-11-08 01:13:17 +11:00
var rootGroup = propertyGroups . First ( x = > x . ParentId = = null ) ;
2016-01-06 11:22:15 +01:00
2013-09-02 15:40:14 +02:00
aggregateTabs . Add ( new Tab < ContentPropertyDisplay >
{
Id = rootGroup . Id ,
Alias = rootGroup . Name ,
2016-01-06 11:22:15 +01:00
Label = _localizedTextService . UmbracoDictionaryTranslate ( rootGroup . Name ) ,
2013-09-02 15:40:14 +02:00
Properties = aggregateProperties ,
IsActive = false
} ) ;
}
//now add the generic properties tab for any properties that don't belong to a tab
2013-09-30 15:42:29 +10:00
var orphanProperties = content . GetNonGroupedProperties ( )
2013-10-22 17:36:46 +11:00
. Where ( x = > IgnoreProperties . Contains ( x . Alias ) = = false ) ; //don't include ignored props
2013-09-02 15:40:14 +02:00
//now add the generic properties tab
2014-11-20 15:19:58 +00:00
var genericproperties = Mapper . Map < IEnumerable < Property > , IEnumerable < ContentPropertyDisplay > > ( orphanProperties ) . ToList ( ) ;
TranslateProperties ( genericproperties ) ;
2013-09-02 15:40:14 +02:00
aggregateTabs . Add ( new Tab < ContentPropertyDisplay >
{
Id = 0 ,
2016-01-06 11:22:15 +01:00
Label = _localizedTextService . Localize ( "general/properties" ) ,
2013-09-02 15:40:14 +02:00
Alias = "Generic properties" ,
2014-11-20 15:19:58 +00:00
Properties = genericproperties
2013-09-02 15:40:14 +02:00
} ) ;
//set the first tab to active
aggregateTabs . First ( ) . IsActive = true ;
return aggregateTabs ;
}
2013-10-09 15:07:09 +02:00
2014-11-20 15:19:58 +00:00
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 )
{
2016-01-06 11:22:15 +01:00
prop . Label = _localizedTextService . UmbracoDictionaryTranslate ( prop . Label ) ;
prop . Description = _localizedTextService . UmbracoDictionaryTranslate ( prop . Description ) ;
2014-11-20 15:19:58 +00:00
}
}
2013-09-02 15:40:14 +02:00
}
}