public async Task BuildDisplayAsync(ContentItem contentItem, BuildDisplayContext context)
        {
            var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

            if (contentTypeDefinition == null)
            {
                return;
            }

            foreach (var displayDriver in _displayDrivers)
            {
                try
                {
                    var result = await displayDriver.BuildDisplayAsync(contentItem, context);

                    if (result != null)
                    {
                        await result.ApplyAsync(context);
                    }
                }
                catch (Exception ex)
                {
                    InvokeExtensions.HandleException(ex, _logger, displayDriver.GetType().Name, nameof(BuildDisplayAsync));
                }
            }

            var settings   = contentTypeDefinition?.GetSettings <ContentTypeSettings>();
            var stereotype = settings?.Stereotype ?? String.Empty;

            foreach (var contentTypePartDefinition in contentTypeDefinition.Parts)
            {
                var partName      = contentTypePartDefinition.Name;
                var partTypeName  = contentTypePartDefinition.PartDefinition.Name;
                var partActivator = _contentPartFactory.GetTypeActivator(partTypeName);
                var part          = contentItem.Get(partActivator.Type, partName) as ContentPart;

                if (part == null)
                {
                    continue;
                }

                var contentType        = contentTypePartDefinition.ContentTypeDefinition.Name;
                var partDisplayDrivers = _contentPartDisplayDriverResolver.GetDisplayModeDrivers(partTypeName, contentTypePartDefinition.DisplayMode());
                foreach (var partDisplayDriver in partDisplayDrivers)
                {
                    try
                    {
                        var result = await partDisplayDriver.BuildDisplayAsync(part, contentTypePartDefinition, context);

                        if (result != null)
                        {
                            await result.ApplyAsync(context);
                        }
                    }
                    catch (Exception ex)
                    {
                        InvokeExtensions.HandleException(ex, _logger, partDisplayDrivers.GetType().Name, nameof(BuildDisplayAsync));
                    }
                }
                var tempContext = context;

                // Create a custom ContentPart shape that will hold the fields for dynamic content part (not implicit parts)
                // This allows its fields to be grouped and templated

                if (part.GetType() == typeof(ContentPart) && partTypeName != contentTypePartDefinition.ContentTypeDefinition.Name)
                {
                    var shapeType = context.DisplayType != "Detail" ? "ContentPart_" + context.DisplayType : "ContentPart";

                    var shapeResult = new ShapeResult(shapeType, ctx => ctx.ShapeFactory.CreateAsync(shapeType, () => new ValueTask <IShape>(new ZoneHolding(() => ctx.ShapeFactory.CreateAsync("Zone")))));
                    shapeResult.Differentiator(partName);
                    shapeResult.Name(partName);
                    shapeResult.Location("Content");
                    shapeResult.OnGroup(context.GroupId);
                    shapeResult.Displaying(ctx =>
                    {
                        var displayTypes = new[] { String.Empty, "_" + ctx.Shape.Metadata.DisplayType };

                        foreach (var displayType in displayTypes)
                        {
                            // eg. ServicePart,  ServicePart.Summary
                            ctx.Shape.Metadata.Alternates.Add($"{partTypeName}{displayType}");

                            // [ContentType]_[DisplayType]__[PartType]
                            // e.g. LandingPage-ServicePart, LandingPage-ServicePart.Summary
                            ctx.Shape.Metadata.Alternates.Add($"{contentType}{displayType}__{partTypeName}");

                            if (!String.IsNullOrEmpty(stereotype))
                            {
                                // [Stereotype]_[DisplayType]__[PartType],
                                // e.g. Widget-ServicePart
                                ctx.Shape.Metadata.Alternates.Add($"{stereotype}{displayType}__{partTypeName}");
                            }
                        }

                        if (partTypeName == partName)
                        {
                            return;
                        }

                        foreach (var displayType in displayTypes)
                        {
                            // [ContentType]_[DisplayType]__[PartName]
                            // e.g. Employee-Address1, Employee-Address2
                            ctx.Shape.Metadata.Alternates.Add($"{contentType}{displayType}__{partName}");

                            if (!String.IsNullOrEmpty(stereotype))
                            {
                                // [Stereotype]_[DisplayType]__[PartType]__[PartName]
                                // e.g. Widget-Services
                                ctx.Shape.Metadata.Alternates.Add($"{stereotype}{displayType}__{partTypeName}__{partName}");
                            }
                        }
                    });

                    await shapeResult.ApplyAsync(context);

                    var contentPartShape = shapeResult.Shape;

                    // Make the ContentPart name property available on the shape
                    contentPartShape.Properties[partTypeName]  = part.Content;
                    contentPartShape.Properties["ContentItem"] = part.ContentItem;

                    context = new BuildDisplayContext(shapeResult.Shape, context.DisplayType, context.GroupId, context.ShapeFactory, context.Layout, context.Updater)
                    {
                        // With a new display context we have the default FindPlacementDelegate that returns null, so we reuse the delegate from the temp context.
                        FindPlacement = tempContext.FindPlacement,
                    };
                }

                foreach (var contentPartFieldDefinition in contentTypePartDefinition.PartDefinition.Fields)
                {
                    var fieldDisplayDrivers = _contentFieldDisplayDriverResolver.GetDisplayModeDrivers(contentPartFieldDefinition.FieldDefinition.Name, contentPartFieldDefinition.DisplayMode());
                    foreach (var fieldDisplayDriver in fieldDisplayDrivers)
                    {
                        try
                        {
                            var result = await fieldDisplayDriver.BuildDisplayAsync(part, contentPartFieldDefinition, contentTypePartDefinition, context);

                            if (result != null)
                            {
                                await result.ApplyAsync(context);
                            }
                        }
                        catch (Exception ex)
                        {
                            InvokeExtensions.HandleException(ex, _logger, fieldDisplayDriver.GetType().Name, nameof(BuildDisplayAsync));
                        }
                    }
                }

                context = tempContext;
            }
        }
Example #2
0
        public async Task BuildDisplayAsync(ContentItem contentItem, BuildDisplayContext context)
        {
            var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

            if (contentTypeDefinition == null)
            {
                return;
            }

            foreach (var displayDriver in _displayDrivers)
            {
                try
                {
                    var result = await displayDriver.BuildDisplayAsync(contentItem, context);

                    if (result != null)
                    {
                        await result.ApplyAsync(context);
                    }
                }
                catch (Exception ex)
                {
                    InvokeExtensions.HandleException(ex, Logger, displayDriver.GetType().Name, nameof(BuildDisplayAsync));
                }
            }

            foreach (var contentTypePartDefinition in contentTypeDefinition.Parts)
            {
                var partName      = contentTypePartDefinition.Name;
                var partTypeName  = contentTypePartDefinition.PartDefinition.Name;
                var contentType   = contentTypePartDefinition.ContentTypeDefinition.Name;
                var partActivator = _contentPartFactory.GetTypeActivator(partTypeName);
                var part          = contentItem.Get(partActivator.Type, partName) as ContentPart;

                if (part != null)
                {
                    var partDisplayDrivers = _contentPartDisplayDriverResolver.GetDisplayModeDrivers(partTypeName, contentTypePartDefinition.DisplayMode());
                    foreach (var partDisplayDriver in partDisplayDrivers)
                    {
                        try
                        {
                            var result = await partDisplayDriver.BuildDisplayAsync(part, contentTypePartDefinition, context);

                            if (result != null)
                            {
                                await result.ApplyAsync(context);
                            }
                        }
                        catch (Exception ex)
                        {
                            InvokeExtensions.HandleException(ex, Logger, partDisplayDrivers.GetType().Name, nameof(BuildDisplayAsync));
                        }
                    }
                    // TODO: This can be removed in a future release as the recommended way is to use ContentOptions.
                    // Iteratate existing driver registrations as multiple drivers maybe not be registered with ContentOptions.
                    foreach (var displayDriver in _partDisplayDrivers)
                    {
                        try
                        {
                            var result = await displayDriver.BuildDisplayAsync(part, contentTypePartDefinition, context);

                            if (result != null)
                            {
                                await result.ApplyAsync(context);
                            }
                        }
                        catch (Exception ex)
                        {
                            InvokeExtensions.HandleException(ex, Logger, displayDriver.GetType().Name, nameof(BuildDisplayAsync));
                        }
                    }
                    var tempContext = context;

                    // Create a custom ContentPart shape that will hold the fields for dynamic content part (not implicit parts)
                    // This allows its fields to be grouped and templated

                    if (part.GetType() == typeof(ContentPart) && partTypeName != contentTypePartDefinition.ContentTypeDefinition.Name)
                    {
                        var shapeType = context.DisplayType != "Detail" ? "ContentPart_" + context.DisplayType : "ContentPart";

                        var shapeResult = new ShapeResult(shapeType, ctx => ctx.ShapeFactory.CreateAsync(shapeType, () => new ValueTask <IShape>(new ZoneHolding(() => ctx.ShapeFactory.CreateAsync("Zone")))));
                        shapeResult.Differentiator(partName);
                        shapeResult.Location("Content");

                        await shapeResult.ApplyAsync(context);

                        var contentPartShape = shapeResult.Shape;

                        // Make the ContentPart name property available on the shape
                        dynamic dynamicContentPartShape = contentPartShape;
                        dynamicContentPartShape[partTypeName]  = part.Content;
                        dynamicContentPartShape["ContentItem"] = part.ContentItem;

                        contentPartShape.Metadata.Alternates.Add(partTypeName);
                        contentPartShape.Metadata.Alternates.Add($"{contentType}__{partTypeName}");

                        if (context.DisplayType != "Detail")
                        {
                            contentPartShape.Metadata.Alternates.Add($"{partTypeName}_{context.DisplayType}");
                            contentPartShape.Metadata.Alternates.Add($"{contentType}_{context.DisplayType}__{partTypeName}");
                        }

                        if (partName != partTypeName)
                        {
                            contentPartShape.Metadata.Alternates.Add($"{contentType}__{partName}");

                            if (context.DisplayType != "Detail")
                            {
                                contentPartShape.Metadata.Alternates.Add($"{contentType}_{context.DisplayType}__{partName}");
                            }
                        }

                        context = new BuildDisplayContext(shapeResult.Shape, context.DisplayType, context.GroupId, context.ShapeFactory, context.Layout, context.Updater);
                    }

                    foreach (var contentPartFieldDefinition in contentTypePartDefinition.PartDefinition.Fields)
                    {
                        var fieldDisplayDrivers = _contentFieldDisplayDriverResolver.GetDisplayModeDrivers(contentPartFieldDefinition.FieldDefinition.Name, contentPartFieldDefinition.DisplayMode());
                        foreach (var fieldDisplayDriver in fieldDisplayDrivers)
                        {
                            try
                            {
                                var result = await fieldDisplayDriver.BuildDisplayAsync(part, contentPartFieldDefinition, contentTypePartDefinition, context);

                                if (result != null)
                                {
                                    await result.ApplyAsync(context);
                                }
                            }
                            catch (Exception ex)
                            {
                                InvokeExtensions.HandleException(ex, Logger, fieldDisplayDriver.GetType().Name, nameof(BuildDisplayAsync));
                            }
                        }
                        // TODO: This can be removed in a future release as the recommended way is to use ContentOptions.
                        // Iteratate existing driver registrations as multiple drivers maybe not be registered with ContentOptions.
                        foreach (var displayDriver in _fieldDisplayDrivers)
                        {
                            try
                            {
                                var result = await displayDriver.BuildDisplayAsync(part, contentPartFieldDefinition, contentTypePartDefinition, context);

                                if (result != null)
                                {
                                    await result.ApplyAsync(context);
                                }
                            }
                            catch (Exception ex)
                            {
                                InvokeExtensions.HandleException(ex, Logger, displayDriver.GetType().Name, nameof(BuildDisplayAsync));
                            }
                        }
                    }

                    context = tempContext;
                }
            }
        }