public override object FromEditor(ContentPropertyData editorValue, object currentValue)
        {
            string json       = editorValue.Value?.ToString();
            var    modelValue = _deserializer.Deserialize(json);

            if (modelValue == null)
            {
                return(base.FromEditor(editorValue, currentValue));
            }

            JArray fromEditor(ContentBlockModelValue block)
            {
                if (_utils.GetDataType(block.DefinitionId) is IDataType dataType &&
                    dataType.Editor?.GetValueEditor() is IDataValueEditor valueEditor)
                {
                    var propertyData = new ContentPropertyData(block.Content.ToString(), dataType.Configuration);

                    try
                    {
                        var ncJson = valueEditor.FromEditor(propertyData, null)?.ToString();

                        if (!string.IsNullOrWhiteSpace(ncJson))
                        {
                            return(JArray.Parse(ncJson));
                        }
                    }
                    catch
                    {
                        return(block.Content);
                    }
                }

                // Fallback: return the original value
                return(block.Content);
            }

            if (modelValue.Header != null)
            {
                modelValue.Header.Content = fromEditor(modelValue.Header);
            }

            if (modelValue.Blocks?.Any() == true)
            {
                foreach (var block in modelValue.Blocks)
                {
                    block.Content = fromEditor(block);
                }
            }

            return(JsonConvert.SerializeObject(modelValue, Formatting.None));
        }
        public IEnumerable <ValidationResult> Validate(object value, string valueType, object dataTypeConfiguration)
        {
            ContentBlocksModelValue modelValue = _deserializer.Deserialize(value?.ToString());

            if (modelValue == null)
            {
                return(Enumerable.Empty <ValidationResult>());
            }

            Structure structure = (dataTypeConfiguration as ContentBlocksConfiguration)?.Structure
                                  // No configuration passed in -> assume everything
                                  ?? Structure.All;

            var blocksToValidate = GetBlocksToValidate(modelValue, structure);

            if (_runtimeState.SemanticVersion >= "8.7.0")
            {
                // Umbraco 8.7's new complex validation needs to be handled very differently.
                return(ValidateComplex(blocksToValidate));
            }
            else
            {
                return(ValidateSimple(blocksToValidate));
            }
        }
        public IEnumerable <ValidationResult> Validate(object value, string valueType, object dataTypeConfiguration)
        {
            ContentBlocksModelValue modelValue = _deserializer.Deserialize(value?.ToString());

            if (modelValue == null)
            {
                return(Enumerable.Empty <ValidationResult>());
            }

            var validationResults = new List <ValidationResult>();

            Structure layout = (dataTypeConfiguration as ContentBlocksConfiguration)?.Structure
                               // No configuration passed in -> assume everything
                               ?? Structure.All;

            if (modelValue.Header?.IsDisabled == false && layout.HasFlag(Structure.Header))
            {
                validationResults.AddRange(Validate(modelValue.Header));
            }

            var blockValidations = modelValue.Blocks
                                   .Where(block => !block.IsDisabled && layout.HasFlag(Structure.Blocks))
                                   .SelectMany(Validate);

            validationResults.AddRange(blockValidations);

            return(validationResults);
        }
        public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
        {
            ContentBlocksModelValue modelValue = _deserializer.Deserialize(inter?.ToString());

            if (modelValue == null)
            {
                return(Rendering.ContentBlocks.Empty);
            }

            var config = propertyType.DataType.ConfigurationAs <ContentBlocksConfiguration>();

            var header = config.Structure.HasFlag(Structure.Header)
                ? createViewModel(modelValue.Header)
                : null;

            var blocks = config.Structure.HasFlag(Structure.Blocks)
                ? modelValue.Blocks.Select(createViewModel).Where(rm => rm != null).ToList()
                : Enumerable.Empty <IContentBlockViewModel>();

            return(new Rendering.ContentBlocks
            {
                Header = header,
                Blocks = blocks
            });

            IContentBlockViewModel createViewModel(ContentBlockModelValue block)
            {
                if (block == null || block.IsDisabled)
                {
                    return(null);
                }

                IContentBlockDefinitionRepository definitionRepository = Current.Factory.GetInstance <IContentBlockDefinitionRepository>();

                if (definitionRepository == null)
                {
                    return(null);
                }

                IContentBlockDefinition definition = definitionRepository.GetById(block.DefinitionId);

                if (definition == null || definition.Layouts == null || definition.Layouts.Any() == false)
                {
                    return(null);
                }

                IContentBlockLayout layout = definition.Layouts.FirstOrDefault(l => l.Id == block.LayoutId);

                if (layout == null)
                {
                    return(null);
                }

                IPublishedElement content = _nestedContentSingleValueConverter.ConvertIntermediateToObject(owner, propertyType, referenceCacheLevel, block?.Content?.ToString(), preview) as IPublishedElement;

                if (content == null)
                {
                    return(null);
                }

                var contentType = content.GetType();
                var genericViewModelFactoryType = typeof(IContentBlockViewModelFactory <>).MakeGenericType(new[] { contentType });
                var viewModelFactory            = Current.Factory.GetInstance(genericViewModelFactoryType) as IContentBlockViewModelFactory;

                if (viewModelFactory == null)
                {
                    return(null);
                }

                return(viewModelFactory.Create(content, block.Id, block.DefinitionId, block.LayoutId));
            }
        }