5
votes

Our Sitecore content tree is generally split up into global and local (or country-specific) pages to serve customers of our branches. As you'd expect, the global pages show up for all viewers of our site, regardless of their geographic locale, but we have implemented certain fields on the global pages that are localizable, e.g. banner ads, featured content, etc.

We've set up security already so that, for a multilist, a given content editor only sees items on the left-hand side to which they have access. The thing that we're running into is that items chosen by other branch content editors are showing up in the right-hand "selected" area of the multilist and, if the content editor currently viewing the item doesn't have permissions to those, they're showing up as [Item not found]. We've had well-intentioned content editors mistakenly double-click those to remove them, not realizing they're removing content intentionally placed there by other editors. A screenshot of how this looks, using the view of one of our German content editors, is below:

Example of Item not found presentation

What I am trying to determine is if there's a way, using security or other methods, to suppress the [Item not found] messages entirely for items to which the current content editor doesn't have permissions. Any hints for a good way to do this (if it's doable) would be appreciated.

1

1 Answers

6
votes

You can create your own Multilist class inheriting from Sitecore.Shell.Applications.ContentEditor.MultilistEx class and override DoRender() method of this class. In a place where text [Item Not Found] is displayed, check if the item exists but user doesn't have access rights (by trying to retrieve the item with SecurityDisabler) and display proper message.

Then you need to go to core database and register your field type:

sitecore my multilist ex

And finally switch the type of your field to the newly created type - your field will look like this:

sitecore custom multilist field result

The code below is the original reflected MultilistEx code which the changes you need:

using System.Collections;
using System.Web.UI;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Resources;
using Sitecore.SecurityModel;

namespace My.Assembly.Namespace
{
    public class MyMultilistEx : Sitecore.Shell.Applications.ContentEditor.MultilistEx
    {
        protected override void DoRender(HtmlTextWriter output)
        {
            Assert.ArgumentNotNull(output, "output");
            ArrayList selected;
            IDictionary unselected;
            GetSelectedItems(GetItems(Sitecore.Context.ContentDatabase.GetItem(ItemID)), out selected, out unselected);
            ServerProperties["ID"] = ID;
            string disabledMessage = string.Empty;
            if (ReadOnly)
                disabledMessage = " disabled=\"disabled\"";
            output.Write("<input id=\"" + ID + "_Value\" type=\"hidden\" value=\"" + StringUtil.EscapeQuote(Value) + "\" />");
            output.Write("<table" + GetControlAttributes() + ">");
            output.Write("<tr>");
            output.Write("<td class=\"scContentControlMultilistCaption\" width=\"50%\">" + Translate.Text("All") + "</td>");
            output.Write("<td width=\"20\">" + Images.GetSpacer(20, 1) + "</td>");
            output.Write("<td class=\"scContentControlMultilistCaption\" width=\"50%\">" + Translate.Text("Selected") + "</td>");
            output.Write("<td width=\"20\">" + Images.GetSpacer(20, 1) + "</td>");
            output.Write("</tr>");
            output.Write("<tr>");
            output.Write("<td valign=\"top\" height=\"100%\">");
            output.Write("<select id=\"" + ID + "_unselected\" class=\"scContentControlMultilistBox\" multiple=\"multiple\" size=\"10\"" + disabledMessage + " ondblclick=\"javascript:scContent.multilistMoveRight('" + ID + "')\" onchange=\"javascript:document.getElementById('" + ID + "_all_help').innerHTML=selectedIndex>=0?options[selectedIndex].innerHTML:''\" >");
            foreach (DictionaryEntry dictionaryEntry in unselected)
            {
                Item unselectedItem = dictionaryEntry.Value as Item;
                if (unselectedItem != null)
                    output.Write("<option value=\"" + GetItemValue(unselectedItem) + "\">" + unselectedItem.DisplayName + "</option>");
            }
            output.Write("</select>");
            output.Write("</td>");
            output.Write("<td valign=\"top\">");
            RenderButton(output, "Core/16x16/arrow_blue_right.png", "javascript:scContent.multilistMoveRight('" + ID + "')");
            output.Write("<br />");
            RenderButton(output, "Core/16x16/arrow_blue_left.png", "javascript:scContent.multilistMoveLeft('" + ID + "')");
            output.Write("</td>");
            output.Write("<td valign=\"top\" height=\"100%\">");
            output.Write("<select id=\"" + ID + "_selected\" class=\"scContentControlMultilistBox\" multiple=\"multiple\" size=\"10\"" + disabledMessage + " ondblclick=\"javascript:scContent.multilistMoveLeft('" + ID + "')\" onchange=\"javascript:document.getElementById('" + ID + "_selected_help').innerHTML=selectedIndex>=0?options[selectedIndex].innerHTML:''\">");
            for (int index = 0; index < selected.Count; ++index)
            {
                Item selectedItem = selected[index] as Item;
                if (selectedItem != null)
                {
                    output.Write("<option value=\"" + GetItemValue(selectedItem) + "\">" + selectedItem.DisplayName + "</option>");
                }
                else
                {
                    string path = selected[index] as string;
                    if (path != null)
                    {
                        string optionDisabled = string.Empty;
                        Item linkedItem = Sitecore.Context.ContentDatabase.GetItem(path);
                        Item notAccessibleItem;
                        using (new SecurityDisabler())
                        {
                            notAccessibleItem = Sitecore.Context.ContentDatabase.GetItem(path);
                        }

                        string text;

                        if (linkedItem == null && notAccessibleItem != null)
                        {
                            text = notAccessibleItem.DisplayName + " [You don't have access rights to this item]";
                            optionDisabled = " disabled=\"disabled\"";
                        }
                        else
                        {
                            text = linkedItem == null
                                              ? path + ' ' + Translate.Text("[Item not found]")
                                              : linkedItem.DisplayName + ' ' + Translate.Text("[Not in the selection List]");
                        }
                        output.Write("<option value=\"" + path + "\"" + optionDisabled + ">" + text + "</option>");
                    }
                }
            }
            output.Write("</select>");
            output.Write("</td>");
            output.Write("<td valign=\"top\">");
            RenderButton(output, "Core/16x16/arrow_blue_up.png", "javascript:scContent.multilistMoveUp('" + ID + "')");
            output.Write("<br />");
            RenderButton(output, "Core/16x16/arrow_blue_down.png", "javascript:scContent.multilistMoveDown('" + ID + "')");
            output.Write("</td>");
            output.Write("</tr>");
            output.Write("<tr>");
            output.Write("<td valign=\"top\">");
            output.Write("<div style=\"border:1px solid #999999;font:8pt tahoma;padding:2px;margin:4px 0px 4px 0px;height:14px\" id=\"" + ID + "_all_help\"></div>");
            output.Write("</td>");
            output.Write("<td></td>");
            output.Write("<td valign=\"top\">");
            output.Write("<div style=\"border:1px solid #999999;font:8pt tahoma;padding:2px;margin:4px 0px 4px 0px;height:14px\" id=\"" + ID + "_selected_help\"></div>");
            output.Write("</td>");
            output.Write("<td></td>");
            output.Write("</tr>");
            output.Write("</table>");
        }

        private void RenderButton(HtmlTextWriter output, string icon, string click)
        {
            Assert.ArgumentNotNull(output, "output");
            Assert.ArgumentNotNull(icon, "icon");
            Assert.ArgumentNotNull(click, "click");
            ImageBuilder imageBuilder = new ImageBuilder();
            imageBuilder.Src = icon;
            imageBuilder.Width = 16;
            imageBuilder.Height = 16;
            imageBuilder.Margin = "2px";
            if (!ReadOnly)
                imageBuilder.OnClick = click;
            output.Write((imageBuilder).ToString());
        }

    }
}