Sitecore Custom Content Tree

During the past few days, I was working on a Proof of Concept about having a custom content tree. In other words, when the Sitecore Content Tree loads, it shows only items in a specific language. Today, throughout this post, I will show you how to achieve this.

First of all, we need to modify the CodeBeside of the current content tree. Navigate to the following directory:

“Website\sitecore\shell\Applications\Content Manager\Default.aspx”

and change the CodeBeside type from

“Sitecore.Shell.Applications.ContentManager.ContentEditorForm, Sitecore.Client”

to your respective namespace and assembly name. The default.aspx page is the one which is responsible for the main UI of the Content Editor.

When clicking on the expanded icon for each item, using Javascript, Sitecore performs a call to the Execute.aspx page so that a call to the server can be made to retrieve the subitems. So, you will need to create an Execute.aspx page which is as follows:

<%@ Page Language="C#" AutoEventWireup="true" Codebehind="CustomExecutionPage.aspx.cs" Inherits="Sitecore.CustomContentEditor.ExecutePage" %>
<%@ OutputCache Location="None" VaryByParam="none" %>

Note that this is a copy paste from the current Execute.aspx page with only a change in the Codebehind type. Also, if you have specified another name apart from Execute.aspx, you need to modify the Content Editor.js. In the “getExecuteRequest” function, change the name from the URL.

untitled

Great. Now, the fun part, Coding. We need to override the current Sidebar method from the ContentEditorForm.

public class CustomContentEditor : ContentEditorForm
{
    protected override Sidebar GetSidebar()
    {
        var result = new CustomTree
        {
            ID = "Tree",
            DataContext = new DataContext()
            {
                DataViewName = "Master"
            }
        };

        return Assert.ResultNotNull(result);
    }
}

Now, we need to implement the CustomTree Class. The CustomTree class will need to extend Tree from the namespace Sitecore.Shell.Applications.ContentManager.Sidebars and most of the code is from Sitecore. Then you will need to perform your change on the RenderTree Method.

public class CustomTree : Tree
{
    public override string RenderTree(bool showRoot)
    {
        var parent = FolderItem.Parent;

        var inner = FolderItem.ID == RootItem.ID || parent == null 
            ? RenderTree(RootItem, FolderItem, null, string.Empty) 
            : RenderTree(RootItem, parent, null, string.Empty);

        if (!showRoot)
        {
            return inner;
        }

        var output = new HtmlTextWriter(new StringWriter());

        RenderTreeNode(output, RootItem, inner, RootItem.ID == FolderItem.ID);

        return output.InnerWriter.ToString();
    }

    private string RenderTree(Item rootItem, Item currentItem, Item innerItem, string inner, Language language)
    {
        var output = new HtmlTextWriter(new StringWriter());

        if (currentItem.Languages.Contains(language))
        {
            var x = FilterChildren(currentItem);

            foreach (var filterChild in x)
            {
                RenderTreeNode(output, filterChild, innerItem == null || !(filterChild.ID == innerItem.ID)
                        ? string.Empty
                        : inner, filterChild.ID == FolderItem.ID);
            }

            if (currentItem.ID != rootItem.ID)
            {
                var parent = currentItem.Parent;

                if (parent != null)
                {
                    return RenderTree(rootItem, parent, currentItem, output.InnerWriter.ToString());
                }
            }
        }

        return output.InnerWriter.ToString();
    }

    private string RenderTree(Item rootItem, Item currentItem, Item innerItem, string inner)
    {
        var output = new HtmlTextWriter(new StringWriter());

        foreach (var filterChild in FilterChildren(currentItem))
        {
            RenderTreeNode(output, filterChild, innerItem == null || !(filterChild.ID == innerItem.ID) 
                ? string.Empty 
                : inner, filterChild.ID == FolderItem.ID);
        }

        if (currentItem.ID != rootItem.ID)
        {
            var parent = currentItem.Parent;

            if (parent != null)
            {
                return RenderTree(rootItem, parent, currentItem, output.InnerWriter.ToString());
            }
        }
        return output.InnerWriter.ToString();
    }

    public new IEnumerable FilterChildren(Item currentItem)
    {
        var dataView = DataContext.DataView;

        return dataView.GetChildren(currentItem, string.Empty, true, 0, 0, string.Empty).Cast();
    }

    private static string GetStyle(Item item)
    {
        if (item.TemplateID == TemplateIDs.TemplateField)
        {
            return string.Empty;
        }

        var str = item.Appearance.Style;

        if (string.IsNullOrEmpty(str) && (item.Appearance.Hidden || item.RuntimeSettings.IsVirtual || item.IsItemClone))
        {
            str = "color:#666666";
        }

        if (!string.IsNullOrEmpty(str))
        {
            str = " style=\"" + str + "\"";
        }

        return str;
    }

    private string GetNodeID(string shortID)
    {
        return ID + "_Node_" + shortID;
    }

    private static string GetClassName(Item item, bool active)
    {
        return !active ? (!IsItemUIStatic(item) ? "scContentTreeNodeNormal" : "scContentTreeNodeStatic") : "scContentTreeNodeActive";
    }

    private static bool IsItemUIStatic(Item item)
    {
        return item[FieldIDs.UIStaticItem] == "1";
    }

    public override void Refresh(ID selected)
    {
        var text = RenderChildNodes(selected);

        Context.ClientPage.ClientResponse.Eval("scContent.expandTreeNode(\"" + GetNodeID(selected.ToShortID().ToString()) + "\", " + StringUtil.EscapeJavascriptString(text) + ")");
    }

    public override string RenderChildNodes(ID parent)
    {
        var currentItem = FolderItem.Database.GetItem(parent, FolderItem.Language);

        var output = new HtmlTextWriter(new StringWriter());

        if (currentItem != null)
        {
            foreach (Item filterChild in FilterChildren(currentItem))
            {
                RenderTreeNode(output, filterChild, string.Empty, filterChild.ID == FolderItem.ID);
            }
        }

        return output.InnerWriter.ToString();
    }

    private static void RenderTreeNodeIcon(HtmlTextWriter output, Item item)
    {
        output.Write(RenderIcon(item));
    }

    private static string RenderIcon(Item item)
    {
        var urlBuilder = new UrlBuilder(item.Appearance.Icon);

        if (item.Paths.IsMediaItem)
        {
            urlBuilder["rev"] = item.Statistics.Revision;
            urlBuilder["la"] = item.Language.ToString();
        }

        var imageBuilder = new ImageBuilder()
        {
            Src = WebUtil.SafeEncode(urlBuilder.ToString()),
            Width = 16,
            Height = 16,
            Class = "scContentTreeNodeIcon"
        };

        if (!string.IsNullOrEmpty(item.Help.Text))
        {
            imageBuilder.Title = item.Help.Text;
        }

        return imageBuilder.ToString();
    }

    private void RenderTreeNodeGlyph(HtmlTextWriter output, string id, string inner, Item item)
    {
        var imageBuilder = new ImageBuilder();

        if (inner.Length > 0)
        {
            imageBuilder.Src = "images/treemenu_expanded.png";
        }
        else
        {
            bool flag;
            if (!Settings.ContentEditor.CheckHasChildrenOnTreeNodes)
            {
                flag = true;
            }
            else
            {
                var securityCheck = Settings.ContentEditor.CheckSecurityOnTreeNodes ? SecurityCheck.Enable : SecurityCheck.Disable;

                flag = ItemManager.HasChildren(item, securityCheck);
            }

            imageBuilder.Src = flag ? "images/treemenu_collapsed.png" : "images/noexpand15x15.gif";
        }

        imageBuilder.Class = "scContentTreeNodeGlyph";
        imageBuilder.ID = ID + "_Glyph_" + id;
        output.Write(imageBuilder.ToString());
    }
}

Note that the

private void RenderTreeNode(HtmlTextWriter output, Item item, string inner, bool active)

is not shown here.

So, to conclude, here is a brief point-wise what should be done:

  1. Change the codebeside of the Default.aspx page from path Website\sitecore\shell\Applications\Content Manager\Default.aspx
  2. Create or modify the Execute.aspx page found at Website\sitecore\shell\Applications\Content Manager
  3. Modify the Content Editor.js if you have specified another name for the Execute.aspx.
  4. Implement the code for the SideBar.
  5. Implement your new Custom Tree.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s