diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockEditorConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockEditorConverter.cs
index f043c8e66e..5c7fc6f14d 100644
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockEditorConverter.cs
+++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockEditorConverter.cs
@@ -1,6 +1,4 @@
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
+using System;
using Umbraco.Core;
using Umbraco.Core.Models.Blocks;
using Umbraco.Core.Models.PublishedContent;
@@ -10,7 +8,7 @@ using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
///
- /// Converts json block objects into
+ /// Converts JSON block objects into .
///
public sealed class BlockEditorConverter
{
@@ -23,30 +21,52 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
_publishedModelFactory = publishedModelFactory;
}
- public IPublishedElement ConvertToElement(
- BlockItemData data,
- PropertyCacheLevel referenceCacheLevel, bool preview)
+ public IPublishedElement ConvertToElement(BlockItemData data, PropertyCacheLevel referenceCacheLevel, bool preview)
{
- // hack! we need to cast, we have no choice beacuse we cannot make breaking changes.
+ var publishedContentType = GetContentType(data.ContentTypeKey);
+
+ // Only convert element types
+ if (publishedContentType == null || publishedContentType.IsElement == false)
+ {
+ return null;
+ }
+
+ var propertyValues = data.RawPropertyValues;
+
+ // Get the UDI from the deserialized object. If this is empty, we can fallback to checking the 'key' if there is one
+ var key = (data.Udi is GuidUdi gudi) ? gudi.Guid : Guid.Empty;
+ if (key == Guid.Empty && propertyValues.TryGetValue("key", out var keyo))
+ {
+ Guid.TryParse(keyo.ToString(), out key);
+ }
+
+ IPublishedElement element = new PublishedElement(publishedContentType, key, propertyValues, preview, referenceCacheLevel, _publishedSnapshotAccessor);
+ element = _publishedModelFactory.CreateModel(element);
+
+ return element;
+ }
+
+ public Type GetModelType(Guid contentTypeKey)
+ {
+ var publishedContentType = GetContentType(contentTypeKey);
+ if (publishedContentType != null)
+ {
+ var modelType = ModelType.For(publishedContentType.Alias);
+
+ return _publishedModelFactory.MapModelType(modelType);
+ }
+
+ return typeof(IPublishedElement);
+ }
+
+ private IPublishedContentType GetContentType(Guid contentTypeKey)
+ {
+ // HACK! We need to cast, we have no choice because we can't make breaking changes (and we need the GUID overload)
var publishedContentCache = _publishedSnapshotAccessor.PublishedSnapshot.Content as IPublishedContentCache2;
if (publishedContentCache == null)
throw new InvalidOperationException("The published content cache is not " + typeof(IPublishedContentCache2));
- // only convert element types - content types will cause an exception when PublishedModelFactory creates the model
- var publishedContentType = publishedContentCache.GetContentType(data.ContentTypeKey);
- if (publishedContentType == null || publishedContentType.IsElement == false)
- return null;
-
- var propertyValues = data.RawPropertyValues;
-
- // Get the udi from the deserialized object. If this is empty we can fallback to checking the 'key' if there is one
- var key = (data.Udi is GuidUdi gudi) ? gudi.Guid : Guid.Empty;
- if (propertyValues.TryGetValue("key", out var keyo))
- Guid.TryParse(keyo.ToString(), out key);
-
- IPublishedElement element = new PublishedElement(publishedContentType, key, propertyValues, preview, referenceCacheLevel, _publishedSnapshotAccessor);
- element = _publishedModelFactory.CreateModel(element);
- return element;
+ return publishedContentCache.GetContentType(contentTypeKey);
}
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs
index 5d216f2b4c..c1915809fa 100644
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs
+++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs
@@ -1,6 +1,4 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
@@ -51,16 +49,9 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
using (_proflog.DebugDuration($"ConvertPropertyToBlockList ({propertyType.DataType.Id})"))
{
- var configuration = propertyType.DataType.ConfigurationAs();
- var blockConfigMap = configuration.Blocks.ToDictionary(x => x.ContentElementTypeKey);
- var validSettingElementTypes = blockConfigMap.Values.Select(x => x.SettingsElementTypeKey).Where(x => x.HasValue).Distinct().ToList();
-
- var contentPublishedElements = new Dictionary();
- var settingsPublishedElements = new Dictionary();
-
- var layout = new List();
-
var value = (string)inter;
+
+ // Short-circuit on empty values
if (string.IsNullOrWhiteSpace(value)) return BlockListModel.Empty;
var converted = _blockListEditorDataConverter.Deserialize(value);
@@ -68,49 +59,60 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
var blockListLayout = converted.Layout.ToObject>();
- // convert the content data
+ // Get configuration
+ var configuration = propertyType.DataType.ConfigurationAs();
+ var blockConfigMap = configuration.Blocks.ToDictionary(x => x.ContentElementTypeKey);
+ var validSettingsElementTypes = blockConfigMap.Values.Select(x => x.SettingsElementTypeKey).Where(x => x.HasValue).Distinct().ToList();
+
+ // Convert the content data
+ var contentPublishedElements = new Dictionary();
foreach (var data in converted.BlockValue.ContentData)
{
if (!blockConfigMap.ContainsKey(data.ContentTypeKey)) continue;
var element = _blockConverter.ConvertToElement(data, referenceCacheLevel, preview);
if (element == null) continue;
+
contentPublishedElements[element.Key] = element;
}
- // convert the settings data
+
+ // If there are no content elements, it doesn't matter what is stored in layout
+ if (contentPublishedElements.Count == 0) return BlockListModel.Empty;
+
+ // Convert the settings data
+ var settingsPublishedElements = new Dictionary();
foreach (var data in converted.BlockValue.SettingsData)
{
- if (!validSettingElementTypes.Contains(data.ContentTypeKey)) continue;
+ if (!validSettingsElementTypes.Contains(data.ContentTypeKey)) continue;
var element = _blockConverter.ConvertToElement(data, referenceCacheLevel, preview);
if (element == null) continue;
+
settingsPublishedElements[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
- if (contentPublishedElements.Count == 0) return BlockListModel.Empty;
-
+ var layout = new List();
foreach (var layoutItem in blockListLayout)
{
- // get the content reference
- var contentGuidUdi = (GuidUdi)layoutItem.ContentUdi;
+ // Get the content reference
+ var contentGuidUdi = (GuidUdi)layoutItem.ContentUdi;
if (!contentPublishedElements.TryGetValue(contentGuidUdi.Guid, out var contentData))
continue;
- // get the setting reference
- IPublishedElement settingsData = null;
- var settingGuidUdi = layoutItem.SettingsUdi != null ? (GuidUdi)layoutItem.SettingsUdi : null;
- if (settingGuidUdi != null)
- settingsPublishedElements.TryGetValue(settingGuidUdi.Guid, out settingsData);
-
if (!contentData.ContentType.TryGetKey(out var contentTypeKey))
throw new InvalidOperationException("The content type was not of type " + typeof(IPublishedContentType2));
if (!blockConfigMap.TryGetValue(contentTypeKey, out var blockConfig))
continue;
- // this can happen if they have a settings type, save content, remove the settings type, and display the front-end page before saving the content again
- // we also ensure that the content type's match since maybe the settings type has been changed after this has been persisted.
+ // Get the setting reference
+ IPublishedElement settingsData = null;
+ var settingGuidUdi = layoutItem.SettingsUdi != null ? (GuidUdi)layoutItem.SettingsUdi : null;
+ if (settingGuidUdi != null)
+ settingsPublishedElements.TryGetValue(settingGuidUdi.Guid, out settingsData);
+
+ // This can happen if they have a settings type, save content, remove the settings type, and display the front-end page before saving the content again
+ // We also ensure that the content types match, since maybe the settings type has been changed after this has been persisted
if (settingsData != null)
{
if (!settingsData.ContentType.TryGetKey(out var settingsElementTypeKey))
@@ -120,8 +122,13 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
settingsData = null;
}
+ // Get settings type from configuration
+ var settingsType = blockConfig.SettingsElementTypeKey.HasValue
+ ? _blockConverter.GetModelType(blockConfig.SettingsElementTypeKey.Value)
+ : typeof(IPublishedElement);
+
// TODO: This should be optimized/cached, as calling Activator.CreateInstance is slow
- var layoutType = typeof(BlockListItem<,>).MakeGenericType(contentData.GetType(), settingsData?.GetType() ?? typeof(IPublishedElement));
+ var layoutType = typeof(BlockListItem<,>).MakeGenericType(contentData.GetType(), settingsType);
var layoutRef = (BlockListItem)Activator.CreateInstance(layoutType, contentGuidUdi, contentData, settingGuidUdi, settingsData);
layout.Add(layoutRef);