7

I have been going through the book Professional Sitecore 8 Development by Phil Wicklund and Jason Wilkerson. The book has been very helpful to me but I've got an issue I haven't been able to figure out. In Chapter 11, I've followed the section on Customizing Rendering in the Experience Editor. The code given in the book works, in that I can see the new custom renderings. However Sitecore's JavaScript validation has been throwing XHTML errors for each of my placeholders. After researching and debugging for a while, I found that this is because the GetEnd() method that contains the closing </div> tags executes between the closing <code></code> blocks for the rendering and the placeholder.

Here is my main layout:

@using Sitecore.Mvc
<!DOCTYPE html>
<html lang="@Sitecore.Context.Language.CultureInfo.TwoLetterISOLanguageName">
<head>
    <title></title>
    <link rel="stylesheet" href="/Content/foundation.sitecoreextensions.css"/>
</head>
<body class="@(Sitecore.Context.PageMode.IsExperienceEditor ? "edit-mode" : string.Empty)">
    <header>
        @Html.Sitecore().Placeholder("header")
    </header>
    <main>
        @Html.Sitecore().Placeholder("main")
    </main>
    <footer>
        @Html.Sitecore().Placeholder("footer")
    </footer>
</body>
</html>

And here is where the custom rendering HTML is added:

using Sitecore.Mvc.ExperienceEditor.Presentation;

namespace Foundation.SitecoreExtensions.RenderingWrapper.Markers
{
    public class EditorComponentRenderingMarker : IMarker
    {
        private readonly string _componentName;

        public EditorComponentRenderingMarker(string componentName)
        {
            _componentName = componentName;
        }
        public string GetStart()
        {
            const string formatString = "<div class=\"component-wrapper {0}\"><span class=\"wrapper-header\">{1}</span><div class=\"component-content clearfix\">";
            return string.Format(formatString, _componentName.Replace(" ", string.Empty), _componentName);
        }
        public string GetEnd()
        {
            return "</div></div>";
        }
    }
}

And last of all, this is what the rendered HTML looks like, as seen from Developer Tools in FireFox: (just the header component, for brevity)

<header>
    <code type="text/sitecore" chrometype="placeholder" kind="open" id="header" key="header" class="scpm" data-selectable="true">
        <!-- JSON that Sitecore injected -->    </code>
    <code type="text/sitecore" chrometype="rendering" kind="open" hintname="Header" id="r_76115221D7FF46D7AAB859A209E1C829" class="scpm" data-selectable="true">
        <!-- JSON that Sitecore injected -->    </code>
    <div class="component-wrapper Header scEnabledChrome" sc-part-of="placeholder rendering">
        <span class="wrapper-header">Header</span>
        <div class="component-content clearfix">
            <div>
                <!-- My Rendering -->
            </div>
            <code type="text/sitecore" id="scEnclosingTag_r_" chrometype="rendering" kind="close" hintkey="Header" class="scpm"></code>
        </div> <!-- this div needs to come before the preceding code block -->
    </div> <!-- this div as well -->
    <code type="text/sitecore" id="scEnclosingTag_" chrometype="placeholder" kind="close" hintname="header" class="scpm"></code>
</header>

As you can see here, the closing </div> blocks are added between the final two <code> blocks.

I believe GetEnd() is behaving exactly as it should in that it executes right after the component is rendered, so it makes sense that it comes right after the <code> block that marks the end of the rendering. However, I don't understand why Sitecore's JavaScript validation throws an error for this. When I modify the HTML from developer tools and move the closing rendering <code> block just after the two closing </div> tags, the error no longer occurs.

I'm not sure how to fix this error. Is it an error with Sitecore's validation? Or should I put the closing </div> tags somewhere else?

Update:

Here is the method to add my rendering. It includes adding to RenderRendering's disposal list.

using Foundation.SitecoreExtensions.RenderingWrapper.Markers;
using Sitecore;
using Sitecore.Mvc.ExperienceEditor.Presentation;
using Sitecore.Mvc.Pipelines.Response.RenderRendering;

namespace Foundation.SitecoreExtensions.RenderingWrapper
{
    public class AddEditorRenderingWrapper : RenderRenderingProcessor
    {
        public override void Process(RenderRenderingArgs args)
        {
            if (args.Rendered || Context.Site == null || !Context.PageMode.IsExperienceEditorEditing || args.Rendering.RenderingType == "Layout")
            {
                return;
            }

            var marker = GetMarker(args);
            if (marker == null)
            {
                return;
            }

            args.Disposables.Add(new EditorRenderingWrapper(args.Writer, marker));
        }

        private static IMarker GetMarker(RenderRenderingArgs args)
        {
            IMarker marker = null;
            var renderingItem = args.Rendering.RenderingItem;

            if (renderingItem != null)
            {
                marker = new EditorComponentRenderingMarker(renderingItem.Name);
            }

            return marker;
        }
    }
}

EditorRenderingWrapper is simply a class that inherits from Sitecore.Mvc.ExperienceEditor.Presentation.Wrapper and does not add any new code.

And Disposables comes from Sitecore.Mvc.Pipelines.MvcPipelineArgs.Disposables

  • That is w3 standards. It says that you cannot set the div element inside the code element. Here is you can check it. validator.w3.org – Vlad Shpak Dec 20 '16 at 9:07
  • Thank you for the response. My example does not place the div elements inside of the code element, but rather it is coming between the code element used to indicate the end of the rendering and the code element used to indicate the end of the placeholder. I have confirmed using developer tools that the placement of the div tags in between these two separate code elements is triggering an XHTML validation error from Sitecore, but I have not been able to figure out how to move the div tags just before the first code element. – Iceape Dec 20 '16 at 10:27
5

The problem is that your wrapper conflicts with Sitecore Experience Editor wrappers.(refer to Sitecore.MvcExperienceEditor.config)

There are 2 additional processors that add its own wrappers:

Sitecore.Mvc.ExperienceEditor.Pipelines.Response.RenderPlaceholder.AddWrapper
Sitecore.Mvc.ExperienceEditor.Pipelines.Response.RenderRendering.AddWrapper

They are responsible for adding <code></code> tags that identifies start and end of placeholders and renderings.

GetEnd() method is executed on wrapper disposing:

void IDisposable.Dispose()
{
  if (this.disposer.Disposed)
  {
    return;
  }
  this.writer.Write(this.marker.GetEnd());
}

For some reason disposing is called in wrong order. Your wrapper is disposed after Sitecore Experience Editor RenderRendering wrapper.

You don't specified your code that adds your wrapper, but I think there should be something similar to Experience Editor wrapper:

int num = args.Disposables.FindIndex((IDisposable x) => x.GetType() == typeof(Wrapper));
if (num < 0)
{
    num = 0;
}
args.Disposables.Insert(num, new Wrapper(args.Writer, marker));

You can try to change num variable to insert wrappers in correct order. If it doesn't help I would suggest incorporate your wrapper with Experience Editor Rendering wrapper to achieve HTML code that is suitable for Experience Editor.

  • Ah, this makes sense. I will add the code I currently use that takes care of disposing the wrapper so you can see it. – Iceape Dec 20 '16 at 14:01
  • @Iceape I see your code. Try to use code that I have provided and that is used for Experience Editor. – Anton Dec 20 '16 at 15:29
  • Thanks for pointing me in the right direction. It ended up being a typo near the Dispose() method. I wrote an answer giving full detail to the problem. – Iceape Dec 20 '16 at 16:21
2

@Anton pointed me in the direction I needed to go. Long story short, as I was implementing his method and stepping through the code in the debugger, I discovered a typo in my code. After fixing it, Sitecore no longer throws an XHTML validation error.

As for the details, when following the book mentioned above, I created 4 classes. 3 rendering wrapper classes: EditorRenderingWrapper.cs AddEditorRenderingWrapper.cs EndEditorRenderingWrapper.cs

And 1 marker class: EditorComponentRenderingMarker.cs

I posted the code for the EditorComponentRenderingMarker and AddEditorRenderingWrapper classes above. The EditorRenderingWrapper is a wrapper class and just extends the base Wrapper class. It doesn't add any new code, so I didn't post it.

But the culprit was in the 4th class, the EndEditorRenderingWrapper class.

Here is the code:

using System;
using System.Linq;
using Sitecore.Mvc.Pipelines.Response.RenderRendering;

namespace BankDelen.Cadelam.Foundation.SitecoreExtensions.RenderingWrapper
{
    public class EndEditorRenderingWrapper : RenderRenderingProcessor
    {
        public override void Process(RenderRenderingArgs args)
        {
            foreach (IDisposable wrapper in args.Disposables.OfType<EditorRenderingWrapper>())
            {
                wrapper.Dispose();
            }
        }
    }
}

My typo was in the foreach statement. I had accidentally originally written args.Disposables.OfType<EndEditorRenderingWrapper>())

The OfType<T>() method was checking EndEditorRenderingWrapper instead of EditorRenderingWrapper and wrapper.Dispose() was never being hit.

A big thanks to @Anton for helping to improve my understanding of how Sitecore works and helping me find this problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.