private void UpdateBlockListRecursively(BlockEditorData blockListData, Func <Guid> createGuid) { var oldToNew = new Dictionary <Udi, Udi>(); MapOldToNewUdis(oldToNew, blockListData.BlockValue.ContentData, createGuid); MapOldToNewUdis(oldToNew, blockListData.BlockValue.SettingsData, createGuid); for (var i = 0; i < blockListData.References.Count; i++) { var reference = blockListData.References[i]; var hasContentMap = oldToNew.TryGetValue(reference.ContentUdi, out var contentMap); Udi settingsMap = null; var hasSettingsMap = reference.SettingsUdi != null && oldToNew.TryGetValue(reference.SettingsUdi, out settingsMap); if (hasContentMap) { // replace the reference blockListData.References.RemoveAt(i); blockListData.References.Insert(i, new ContentAndSettingsReference(contentMap, hasSettingsMap ? settingsMap : null)); } } // build the layout with the new UDIs var layout = (JArray)blockListData.Layout; layout.Clear(); foreach (var reference in blockListData.References) { layout.Add(JObject.FromObject(new BlockListLayoutItem { ContentUdi = reference.ContentUdi, SettingsUdi = reference.SettingsUdi })); } RecursePropertyValues(blockListData.BlockValue.ContentData, createGuid); RecursePropertyValues(blockListData.BlockValue.SettingsData, createGuid); }
public BlockEditorData?DeserializeAndClean(object?propertyValue) { if (propertyValue == null || string.IsNullOrWhiteSpace(propertyValue.ToString())) { return(null); } BlockEditorData blockEditorData = _dataConverter.Deserialize(propertyValue.ToString() !); if (blockEditorData.BlockValue.ContentData.Count == 0) { // if there's no content ensure there's no settings too blockEditorData.BlockValue.SettingsData.Clear(); return(null); } var contentTypePropertyTypes = new Dictionary <string, Dictionary <string, IPropertyType> >(); // filter out any content that isn't referenced in the layout references foreach (BlockItemData block in blockEditorData.BlockValue.ContentData.Where(x => blockEditorData.References.Any(r => x.Udi is not null && r.ContentUdi == x.Udi))) { ResolveBlockItemData(block, contentTypePropertyTypes); } // filter out any settings that isn't referenced in the layout references foreach (BlockItemData block in blockEditorData.BlockValue.SettingsData.Where(x => blockEditorData.References.Any(r => r.SettingsUdi is not null && x.Udi is not null && r.SettingsUdi == x.Udi))) { ResolveBlockItemData(block, contentTypePropertyTypes); } // remove blocks that couldn't be resolved blockEditorData.BlockValue.ContentData.RemoveAll(x => x.ContentTypeAlias.IsNullOrWhiteSpace()); blockEditorData.BlockValue.SettingsData.RemoveAll(x => x.ContentTypeAlias.IsNullOrWhiteSpace()); return(blockEditorData); }
/// <inheritdoc /> public override object?ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object?inter, bool preview) { // NOTE: The intermediate object is just a JSON string, we don't actually convert from source -> intermediate since source is always just a JSON string using (_proflog.DebugDuration <BlockListPropertyValueConverter>( $"ConvertPropertyToBlockList ({propertyType.DataType.Id})")) { var value = (string?)inter; // Short-circuit on empty values if (string.IsNullOrWhiteSpace(value)) { return(BlockListModel.Empty); } BlockEditorData converted = _blockListEditorDataConverter.Deserialize(value); if (converted.BlockValue.ContentData.Count == 0) { return(BlockListModel.Empty); } IEnumerable <BlockListLayoutItem>?blockListLayout = converted.Layout?.ToObject <IEnumerable <BlockListLayoutItem> >(); if (blockListLayout is null) { return(BlockListModel.Empty); } // Get configuration BlockListConfiguration?configuration = propertyType.DataType.ConfigurationAs <BlockListConfiguration>(); if (configuration is null) { return(null); } var blockConfigMap = configuration.Blocks.ToDictionary(x => x.ContentElementTypeKey); // Convert the content data var contentPublishedElements = new Dictionary <Guid, IPublishedElement>(); foreach (BlockItemData data in converted.BlockValue.ContentData) { if (!blockConfigMap.ContainsKey(data.ContentTypeKey)) { continue; } IPublishedElement?element = _blockConverter.ConvertToElement(data, referenceCacheLevel, preview); if (element == null) { continue; } contentPublishedElements[element.Key] = element; } // 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 <Guid, IPublishedElement>(); var validSettingsElementTypes = blockConfigMap.Values.Select(x => x.SettingsElementTypeKey) .Where(x => x.HasValue).Distinct().ToList(); foreach (BlockItemData data in converted.BlockValue.SettingsData) { if (!validSettingsElementTypes.Contains(data.ContentTypeKey)) { continue; } IPublishedElement?element = _blockConverter.ConvertToElement(data, referenceCacheLevel, preview); if (element is null) { continue; } settingsPublishedElements[element.Key] = element; } // Cache constructors locally (it's tied to the current IPublishedSnapshot and IPublishedModelFactory) var blockListItemActivator = new BlockListItemActivator(_blockConverter); var list = new List <BlockListItem>(); foreach (BlockListLayoutItem layoutItem in blockListLayout) { // Get the content reference var contentGuidUdi = (GuidUdi?)layoutItem.ContentUdi; if (contentGuidUdi is null || !contentPublishedElements.TryGetValue(contentGuidUdi.Guid, out IPublishedElement? contentData)) { continue; } if (!blockConfigMap.TryGetValue( contentData.ContentType.Key, out BlockListConfiguration.BlockConfiguration? blockConfig)) { continue; } // Get the setting reference IPublishedElement?settingsData = null; var settingGuidUdi = (GuidUdi?)layoutItem.SettingsUdi; if (settingGuidUdi is not 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 is not null && (!blockConfig.SettingsElementTypeKey.HasValue || settingsData.ContentType.Key != blockConfig.SettingsElementTypeKey)) { settingsData = null; } // Create instance (use content/settings type from configuration) BlockListItem layoutRef = blockListItemActivator.CreateInstance(blockConfig.ContentElementTypeKey, blockConfig.SettingsElementTypeKey, contentGuidUdi, contentData, settingGuidUdi, settingsData); list.Add(layoutRef); } return(new BlockListModel(list)); } }