diff --git a/src/Umbraco.Core/Models/Blocks/BlockListLayoutReference.cs b/src/Umbraco.Core/Models/Blocks/BlockListLayoutReference.cs index a2fd6c9df9..09c6c76478 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockListLayoutReference.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockListLayoutReference.cs @@ -10,16 +10,32 @@ namespace Umbraco.Core.Models.Blocks [DataContract(Name = "blockListLayout", Namespace = "")] public class BlockListLayoutReference : IBlockElement { - public BlockListLayoutReference(Udi udi, IPublishedElement settings) + public BlockListLayoutReference(Udi udi, IPublishedElement data, IPublishedElement settings) { Udi = udi ?? throw new ArgumentNullException(nameof(udi)); + Data = data ?? throw new ArgumentNullException(nameof(data)); Settings = settings; // can be null } + /// + /// The Id of the data item + /// [DataMember(Name = "udi")] public Udi Udi { get; set; } + /// + /// The settings for the layout item + /// [DataMember(Name = "settings")] public IPublishedElement Settings { get; set; } + + /// + /// The data item referenced + /// + /// + /// This is ignored from serialization since it is just a reference to the actual data element + /// + [IgnoreDataMember] + public IPublishedElement Data { get; set; } } } diff --git a/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs b/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs index 114642f89d..ca687f94a6 100644 --- a/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs +++ b/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs @@ -207,6 +207,31 @@ data: []}"; Assert.IsNotNull(converted); Assert.AreEqual(0, converted.Data.Count()); Assert.AreEqual(0, converted.Layout.Count()); + + // Everthing is ok except the udi reference in the layout doesn't match the data so it will be empty + json = @" +{ + layout: { + '" + Constants.PropertyEditors.Aliases.BlockList + @"': [ + { + 'udi': 'umb://element/1304E1DDAC87439684FE8A399231CB3D', + 'settings': {} + } + ] + }, + data: [ + { + 'contentTypeAlias': 'home', + 'key': '1304E1DD-0000-4396-84FE-8A399231CB3D' + } + ] +}"; + + converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel; + + Assert.IsNotNull(converted); + Assert.AreEqual(1, converted.Data.Count()); + Assert.AreEqual(0, converted.Layout.Count()); } [Test] @@ -247,5 +272,59 @@ data: []}"; Assert.AreEqual(Udi.Parse("umb://element/1304E1DDAC87439684FE8A399231CB3D"), layout0.Udi); } + [Test] + public void Get_Data_From_Layout_Item() + { + var editor = CreateConverter(); + var config = ConfigForMany(); + var propertyType = GetPropertyType(config); + var publishedElement = Mock.Of(); + + var json = @" +{ + layout: { + '" + Constants.PropertyEditors.Aliases.BlockList + @"': [ + { + 'udi': 'umb://element/1304E1DDAC87439684FE8A399231CB3D', + 'settings': {} + }, + { + 'udi': 'umb://element/0A4A416E547D464FABCC6F345C17809A', + 'settings': {} + } + ] + }, + data: [ + { + 'contentTypeAlias': 'home', + 'key': '1304E1DD-AC87-4396-84FE-8A399231CB3D' + }, + { + 'contentTypeAlias': 'home', + 'key': 'E05A0347-0442-4AB3-A520-E048E6197E79' + }, + { + 'contentTypeAlias': 'home', + 'key': '0A4A416E-547D-464F-ABCC-6F345C17809A' + } + ] +}"; + + var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel; + + Assert.IsNotNull(converted); + Assert.AreEqual(3, converted.Data.Count()); + Assert.AreEqual(2, converted.Layout.Count()); + + var item0 = converted.Layout.ElementAt(0); + Assert.AreEqual(Guid.Parse("1304E1DD-AC87-4396-84FE-8A399231CB3D"), item0.Data.Key); + Assert.AreEqual("home", item0.Data.ContentType.Alias); + + var item1 = converted.Layout.ElementAt(1); + Assert.AreEqual(Guid.Parse("0A4A416E-547D-464F-ABCC-6F345C17809A"), item1.Data.Key); + Assert.AreEqual("home", item1.Data.ContentType.Alias); + + } + } } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs index ab289f048c..3878b8d605 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs @@ -59,12 +59,13 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { var configuration = propertyType.DataType.ConfigurationAs(); var contentTypes = configuration.ElementTypes; - var elements = contentTypes.Length == 1 + var elements = (contentTypes.Length == 1 ? (IList)_publishedModelFactory.CreateModelList(contentTypes[0].Alias) - : new List(); + : new List()) + .ToDictionary(x => x.Key, x => x); var layout = new List(); - var model = new BlockListModel(elements, layout); + var model = new BlockListModel(elements.Values, layout); var value = (string)inter; if (string.IsNullOrWhiteSpace(value)) return model; @@ -86,7 +87,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { var element = _blockConverter.ConvertToElement(data, BlockEditorPropertyEditor.ContentTypeAliasPropertyKey, referenceCacheLevel, preview); if (element == null) continue; - elements.Add(element); + elements[element.Key] = element; } // if there's no elements just return since if there's no data it doesn't matter what is stored in layout @@ -100,15 +101,17 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters // the result of this can be null, that's ok var element = _blockConverter.ConvertToElement(settingsJson, BlockEditorPropertyEditor.ContentTypeAliasPropertyKey, referenceCacheLevel, preview); - if (!Udi.TryParse(blockListLayout.Value("udi"), out var udi)) + if (!Udi.TryParse(blockListLayout.Value("udi"), out var udi) || !(udi is GuidUdi guidUdi)) continue; - var layoutRef = new BlockListLayoutReference(udi, element); + // get the data reference + if (!elements.TryGetValue(guidUdi.Guid, out var data)) + continue; + + var layoutRef = new BlockListLayoutReference(udi, data, element); layout.Add(layoutRef); } - - return model; } } diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 1c4121da0c..79b24175ea 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -108,6 +108,7 @@ namespace Umbraco.Web.Runtime composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); + composition.RegisterUnique(); // register the umbraco helper - this is Transient! very important! // also, if not level.Run, we cannot really use the helper (during upgrade...)