Tuesday, 17 February 2015

The rich page/experience editor

As we move down the path of personalisation in Sitecore we are finding that our editors are spending more and more time in the "Page/Experience Editor" and less time in the "Content Editor". This means that editors are starting to expect to be able to do all of their editing in the "Experience Editor", and why shouldn't they? We are rendering the page in edit mode, we have full control, lets use it.

Below is a simple example of what can be done using a carousel as an example. Now put aside your concerns about carousels (http://shouldiuseacarousel.com/), this is designed as a thought provoking exercise aimed at getting you to think about how you can make life better for you content editors within your own project domain, not as a way of building a carousel.

The reason that a carousel is useful as a thought provoker is that it has some characteristics that don't make it feel like an easy fit for the experience editor. These include
  • Unknown number of slides
  • The order of content in a carousel is important - the first slide gets more views then the last
So without further adieu lets show you what the experience editor experience could be like


Notice the new buttons? This style of functionality has typically been implemented using edit frames and there is a lot of content there around it (e.g. http://www.cmsbestpractices.com/how-to-properly-use-sitecore-edit-frames/), but  we can also include these buttons directly into your site and and simplify the editing experience.

Now what have I actually done to get this running, well there are two main things, the first being accept that you are going to need to do different things in edit mode to delivery mode. This is as simple as adding an if(or multiple ifs) to your view layer to check what the current page mode is.


The next step is to understand what commands are available to you and how you can additional commands. As mentioned before, traditionally these commands would be implemented using the edit frames functionality and the commands that I am using are exactly the same. 

If you were to configure an edit frame or sub layout with a series of commands and inspect it you would see something like the following.


Essentially each edit frame button/command is a JavaScript click event with a command, webedit:new, and an item id associated with it. Knowing that Sitecore uses this approach to triggering commands we can build our own renderings taking this into account. So going back to the buttons in my carousel, each button essentially has the same JavaScript rendered from an MVC helper as demonstrated below.

namespace Website.Helpers
{
    using System.Web;
    using Sitecore.Data.Items;

    public class PageEditorHelpers
    {
        public HtmlString NewItemButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('webedit:new(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }        
        
        public HtmlString DeleteItemButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('webedit:delete(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }        
        
        public HtmlString MoveItemUpButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('item:moveup(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }        
        
        public HtmlString MoveItemDownButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('item:movedown(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }

        public HtmlString SortItemsButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('webedit:sortcontent(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }
    }
}

Once we have the helper setup it's easy to include them in the markup and customise the experience for our editors.

Now keep in mind that this was a thought provoking exercise and you can create any custom command you like, or add any code you like. What can you do for your editors? The ideas become endless and all of those custom UI's you build for you public users can now also be used to enhance the experience for you editors.