orchardcmsorchardcms-1.10

Is it possible in Orchard to dynamically change HTML in a shape right before rendering?


This is the markup for Content.ThumbnailSummary.cshtml, a custom DisplayType I use to render ContentItems as clickable thumbnails with their contents absolutely positioned over them.

@using Orchard.Utility.Extensions;
@{
    var contentTypeClassName = ((string)Model.ContentItem.ContentType).HtmlClassify();
}
<a class="content-item @contentTypeClassName thumbnail-summary">
    @Display(Model.Header)
    <div class="thumbnail-summary-inner">
        @Display(Model.Content)
    </div>
    @Display(Model.Footer)
</a>

The problem is that out of the box most Parts and Fields get rendered as links or paragraphs containing links, and nested <a> tags mess up DOM rendering pretty badly in most browsers. A ThumbnailSummary should never contain any links.

I could create alternates for every field and part, or I could remove everything by default in placement and only add rules for specific cases as I need them. But that would be pretty tedious and defeats a lot of the benefits of placement, so I was hoping I could somehow strip or replace all <a> tags in code only for shapes with this DisplayType.

I've been looking in this direction but I'm not sure if it's viable:

public class Shapes : IShapeTableProvider
{
    public void Discover(ShapeTableBuilder builder)
    {
        builder.Describe("Content")
            .OnDisplaying(displaying =>
            {
                if (displaying.ShapeMetadata.DisplayType == "ThumbnailSummary")
                {             
                    // Do something here???
                }
            });
    }
}

Solution

  • You are almost right, instead of a provider add a class that inherits from Orchard.DisplayManagement.Implementation.ShapeDisplayEvents or implement IShapeDisplayEvents yourself.

    I've done this myself to remove certain functionality from admin area that cannot be disabled via feature or permission.

    The code should look like this

    public class MyShapeDisplayEvents : Orchard.DisplayManagement.Implementation.ShapeDisplayEvents
    {
      public override void Displayed(Orchard.DisplayManagement.Implementation.ShapeDisplayedContext context)
      {
        if (context.Shape is Orchard.DisplayManagement.Shapes.Shape)
        {
          Orchard.DisplayManagement.Shapes.Shape lShape = (Orchard.DisplayManagement.Shapes.Shape)context.Shape;
    
          if (lShape.Metadata.Type == "Layout")
          { 
            string lChildContent = context.ChildContent.ToHtmlString();
    
            // do something with the content like removing tags
    
            context.ChildContent = new System.Web.HtmlString(lChildContent);
          }
    
          ...