diff --git a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeDisplay.cs
index ce9e2b7586..c76f4b3a9d 100644
--- a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeDisplay.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeDisplay.cs
@@ -27,5 +27,14 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "locked")]
[ReadOnly(true)]
public bool Locked { get; set; }
+
+ ///
+ /// This is required for the UI editor to know if this particular property belongs to
+ /// an inherited item or the current item.
+ ///
+ [DataMember(Name = "contentTypeId")]
+ [ReadOnly(true)]
+ public int ContentTypeId { get; set; }
+
}
}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs
index 2c9f9939d1..1aa6825e19 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs
@@ -255,12 +255,14 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(g => g.Editor, expression => expression.Ignore())
.ForMember(g => g.View, expression => expression.Ignore())
.ForMember(g => g.Config, expression => expression.Ignore())
+ .ForMember(g => g.ContentTypeId, expression => expression.Ignore())
.ForMember(g => g.Locked, exp => exp.Ignore());
config.CreateMap()
.ForMember(g => g.Editor, expression => expression.Ignore())
.ForMember(g => g.View, expression => expression.Ignore())
.ForMember(g => g.Config, expression => expression.Ignore())
+ .ForMember(g => g.ContentTypeId, expression => expression.Ignore())
.ForMember(g => g.Locked, exp => exp.Ignore());
#endregion
diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs
index f8d0af4bdf..6409fe8009 100644
--- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs
@@ -41,6 +41,26 @@ namespace Umbraco.Web.Models.Mapping
.FirstOrDefault(x => x != null);
}
+ ///
+ /// Gets the content type that defines a property group, within a composition.
+ ///
+ /// The composition.
+ /// The identifier of the property type.
+ /// The composition content type that defines the specified property group.
+ private static IContentTypeComposition GetContentTypeForPropertyType(IContentTypeComposition contentType, int propertyTypeId)
+ {
+ // test local property types
+ if (contentType.PropertyTypes.Any(x => x.Id == propertyTypeId))
+ return contentType;
+
+ // test composition property types
+ // .ContentTypeComposition is just the local ones, not recursive,
+ // so we have to recurse here
+ return contentType.ContentTypeComposition
+ .Select(x => GetContentTypeForPropertyType(x, propertyTypeId))
+ .FirstOrDefault(x => x != null);
+ }
+
protected override IEnumerable> ResolveCore(IContentTypeComposition source)
{
// deal with groups
@@ -58,7 +78,7 @@ namespace Umbraco.Web.Models.Mapping
ContentTypeId = source.Id
};
- group.Properties = MapProperties(tab.PropertyTypes, tab.Id, false);
+ group.Properties = MapProperties(tab.PropertyTypes, source, tab.Id, false);
groups.Add(group);
}
@@ -85,7 +105,7 @@ namespace Umbraco.Web.Models.Mapping
ParentTabContentTypeNames = new[] { definingContentType.Name }
};
- group.Properties = MapProperties(tab.PropertyTypes, tab.Id, true);
+ group.Properties = MapProperties(tab.PropertyTypes, definingContentType, tab.Id, true);
groups.Add(group);
}
@@ -94,14 +114,20 @@ namespace Umbraco.Web.Models.Mapping
// add generic properties local to this content type
var entityGenericProperties = source.PropertyTypes.Where(x => x.PropertyGroupId == null);
- genericProperties.AddRange(MapProperties(entityGenericProperties, PropertyGroupBasic.GenericPropertiesGroupId, false));
+ genericProperties.AddRange(MapProperties(entityGenericProperties, source, PropertyGroupBasic.GenericPropertiesGroupId, false));
// add generic properties inherited through compositions
var localGenericPropertyIds = genericProperties.Select(x => x.Id).ToArray();
var compositionGenericProperties = source.CompositionPropertyTypes
.Where(x => x.PropertyGroupId == null // generic
&& localGenericPropertyIds.Contains(x.Id) == false); // skip those that are local
- genericProperties.AddRange(MapProperties(compositionGenericProperties, PropertyGroupBasic.GenericPropertiesGroupId, true));
+ foreach (var compositionGenericProperty in compositionGenericProperties)
+ {
+ var definingContentType = GetContentTypeForPropertyType(source, compositionGenericProperty.Id);
+ if (definingContentType == null)
+ throw new Exception("PropertyType with id=" + compositionGenericProperty.Id + " was not found on any of the content type's compositions.");
+ genericProperties.AddRange(MapProperties(new [] { compositionGenericProperty }, definingContentType, PropertyGroupBasic.GenericPropertiesGroupId, true));
+ }
// if there are any generic properties, add the corresponding tab
if (genericProperties.Any())
@@ -165,7 +191,7 @@ namespace Umbraco.Web.Models.Mapping
return groups.OrderBy(x => x.SortOrder);
}
- private IEnumerable MapProperties(IEnumerable properties, int groupId, bool inherited)
+ private IEnumerable MapProperties(IEnumerable properties, IContentTypeBase contentType, int groupId, bool inherited)
{
var mappedProperties = new List();
@@ -179,20 +205,21 @@ namespace Umbraco.Web.Models.Mapping
mappedProperties.Add(new TPropertyType
{
- Id = p.Id,
- Alias = p.Alias,
- Description = p.Description,
- Editor = p.PropertyEditorAlias,
- Validation = new PropertyTypeValidation { Mandatory = p.Mandatory, Pattern = p.ValidationRegExp },
- Label = p.Name,
- View = propertyEditor.ValueEditor.View,
- Config = propertyEditor.PreValueEditor.ConvertDbToEditor(propertyEditor.DefaultPreValues, preValues) ,
- //Value = "",
- GroupId = groupId,
- Inherited = inherited,
- DataTypeId = p.DataTypeDefinitionId,
- SortOrder = p.SortOrder
- });
+ Id = p.Id,
+ Alias = p.Alias,
+ Description = p.Description,
+ Editor = p.PropertyEditorAlias,
+ Validation = new PropertyTypeValidation {Mandatory = p.Mandatory, Pattern = p.ValidationRegExp},
+ Label = p.Name,
+ View = propertyEditor.ValueEditor.View,
+ Config = propertyEditor.PreValueEditor.ConvertDbToEditor(propertyEditor.DefaultPreValues, preValues),
+ //Value = "",
+ GroupId = groupId,
+ Inherited = inherited,
+ DataTypeId = p.DataTypeDefinitionId,
+ SortOrder = p.SortOrder,
+ ContentTypeId = contentType.Id
+ });
}
return mappedProperties;