Skip to content

Instantly share code, notes, and snippets.

@KKings
Last active April 14, 2020 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KKings/7b092c77f62d4b3e31a4a494cd17fefb to your computer and use it in GitHub Desktop.
Save KKings/7b092c77f62d4b3e31a4a494cd17fefb to your computer and use it in GitHub Desktop.
Helix Support Sitecore Field Extensions, allowing filtering by Base Templates
namespace Sitecore.Foundation.SitecoreExtensions.FieldTypes
{
using System;
using System.Linq;
using Sitecore.Data.Items;
using Sitecore.Foundation.SitecoreExtensions.Extensions;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
using Control = System.Web.UI.Control;
/// <summary>
/// Supporting class to allow additional paramters to filtered the tree
/// </summary>
internal class FilteredDataTreeView : DataTreeview
{
public string[] ExcludeTemplatesForDisplay
{
get { return this.GetViewStateProperty("ExcludeTemplatesForDisplay", null) as string[]; }
set { this.SetViewStateProperty("ExcludeTemplatesForDisplay", value, null); }
}
public string[] ExcludeTemplatesForSelection
{
get { return this.GetViewStateProperty("ExcludeTemplatesForSelection", null) as string[]; }
set { this.SetViewStateProperty("ExcludeTemplatesForSelection", value, null); }
}
public string[] IncludeTemplatesForDisplay
{
get { return this.GetViewStateProperty("IncludeTemplatesForDisplay", null) as string[]; }
set { this.SetViewStateProperty("IncludeTemplatesForDisplay", value, null); }
}
public string[] IncludeTemplatesForSelection
{
get { return this.GetViewStateProperty("IncludeTemplatesForSelection", null) as string[]; }
set { this.SetViewStateProperty("IncludeTemplatesForSelection", value, null); }
}
public string[] IncludeBaseTemplatesForSelection
{
get { return this.GetViewStateProperty("IncludeBaseTemplatesForSelections", null) as string[]; }
set { this.SetViewStateProperty("IncludeBaseTemplatesForSelections", value, null); }
}
public override void HandleMessage(Message message)
{
if (message.Name == "event:keydown")
{
Sitecore.Context.ClientPage.ClientResponse.ClosePopups(false);
message.CancelDispatch = true;
}
else
{
base.HandleMessage(message);
}
}
protected override void Populate(DataContext dataContext, Control control, Item root, Item folder, string selectedIDs)
{
if (this.ExcludeTemplatesForDisplay == null && this.IncludeTemplatesForDisplay == null)
{
base.Populate(dataContext, control, root, folder, selectedIDs);
}
else
{
if (this.IncludeTemplatesForDisplay != null && !this.IncludeTemplatesForDisplay.Contains(root.TemplateName)
|| this.ExcludeTemplatesForDisplay != null && this.ExcludeTemplatesForDisplay.Contains(root.TemplateName))
{
return;
}
base.Populate(dataContext, control, root, folder, selectedIDs);
foreach (var dataTreeNode in control.Controls.OfType<DataTreeNode>().Where(p => p.Visible && p.Expandable))
{
if (!String.IsNullOrEmpty(dataTreeNode.ItemID))
{
var obj = dataContext.GetItem(dataTreeNode.ItemID);
if (obj == null)
{
continue;
}
var flag = false;
foreach (Item child in obj.Children)
{
if (this.IncludeTemplatesForDisplay != null && this.IncludeTemplatesForDisplay.Contains(child.TemplateName))
{
flag = true;
break;
}
if (this.ExcludeTemplatesForDisplay != null && !this.ExcludeTemplatesForDisplay.Contains(child.TemplateName))
{
flag = true;
break;
}
}
if (!flag)
{
dataTreeNode.Expandable = false;
dataTreeNode.Expanded = false;
}
}
}
}
}
protected override TreeNode GetTreeNode(Item item, Control parent)
{
var treeNode = base.GetTreeNode(item, parent);
if (this.ExcludeTemplatesForSelection != null && this.ExcludeTemplatesForSelection.Contains(item.TemplateName))
{
treeNode.Enabled = false;
}
if (this.ExcludeTemplatesForDisplay != null && this.ExcludeTemplatesForDisplay.Contains(item.TemplateName))
{
treeNode.Visible = false;
}
if (this.IncludeTemplatesForSelection != null && !this.IncludeTemplatesForSelection.Contains(item.TemplateName))
{
treeNode.Enabled = false;
}
if (this.IncludeTemplatesForDisplay != null && !this.IncludeTemplatesForDisplay.Contains(item.TemplateName))
{
treeNode.Visible = false;
}
if (this.IncludeBaseTemplatesForSelection != null &&
!this.IncludeBaseTemplatesForSelection.Any(t => item.IsDerived(Sitecore.Data.ID.Parse(t))))
{
treeNode.Enabled = false;
}
return treeNode;
}
protected override void NodeClicked(Message message, TreeNode node)
{
var dataTreeNode = node as DataTreeNode;
if (dataTreeNode != null && !dataTreeNode.Enabled)
{
Sitecore.Context.ClientPage.ClientResponse.ClosePopups(false);
message.CancelDispatch = true;
}
else
{
base.NodeClicked(message, node);
}
}
}
}
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
<sitecore>
<controlSources>
<source patch:before="*[@namespace='Sitecore.Shell.Applications.ContentEditor']" mode="on"
namespace="Sitecore.Foundation.SitecoreExtensions.FieldTypes" assembly="Sitecore.Foundation.SitecoreExtensions" prefix="content" />
</controlSources>
</sitecore>
</configuration>
namespace Sitecore.Foundation.SitecoreExtensions.FieldTypes
{
using System;
using System.Web.UI.WebControls;
using Sitecore;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
/// <summary>
/// Extends the <see cref="Sitecore.Shell.Applications.ContentEditor.Tree"/> by
/// adding in support to filter the selectable templates in a Tree by the base templates
/// Syntax for the Field Source: Datasource={Insert Sitecore Query or Item Path}&IncludeBaseTemplatesForSelection={Insert GUID}
/// </summary>
public class Tree : Sitecore.Shell.Applications.ContentEditor.Tree
{
#region Additional Fields for Filtering
public string ExcludeTemplatesForDisplay
{
get
{
return this.GetViewStateString("ExcludeTemplatesForDisplay");
}
set
{
Assert.ArgumentNotNull(value, "value");
this.SetViewStateString("ExcludeTemplatesForDisplay", value);
}
}
public string ExcludeTemplatesForSelection
{
get
{
return this.GetViewStateString("ExcludeTemplatesForSelection");
}
set
{
Assert.ArgumentNotNull(value, "value");
this.SetViewStateString("ExcludeTemplatesForSelection", value);
}
}
public string IncludeTemplatesForDisplay
{
get
{
return this.GetViewStateString("IncludeTemplatesForDisplay");
}
set
{
Assert.ArgumentNotNull(value, "value");
this.SetViewStateString("IncludeTemplatesForDisplay", value);
}
}
public string IncludeTemplatesForSelection
{
get
{
return this.GetViewStateString("IncludeTemplatesForSelection");
}
set
{
Assert.ArgumentNotNull(value, "value");
this.SetViewStateString("IncludeTemplatesForSelection", value);
}
}
public string IncludeBaseTemplatesForSelection
{
get
{
return this.GetViewStateString("IncludeBaseTemplatesForSelection");
}
set
{
Assert.ArgumentNotNull(value, "value");
this.SetViewStateString("IncludeBaseTemplatesForSelection", value);
}
}
#endregion
/// <summary>
/// Overrides the source property to pull out the DataSource
/// and filterable properties
/// </summary>
public new string Source
{
get { return base.Source; }
set
{
if (value == null)
{
base.Source = value;
}
else
{
var contextItem = Client.ContentDatabase.GetItem(this.ItemID);
var datasourceValue = StringUtil.ExtractParameter("DataSource", value).Trim();
if (datasourceValue.StartsWith("query:"))
{
this.ExcludeTemplatesForSelection = StringUtil.ExtractParameter("ExcludeTemplatesForSelection", value).Trim();
this.IncludeTemplatesForSelection = StringUtil.ExtractParameter("IncludeTemplatesForSelection", value).Trim();
this.IncludeTemplatesForDisplay = StringUtil.ExtractParameter("IncludeTemplatesForDisplay", value).Trim();
this.ExcludeTemplatesForDisplay = StringUtil.ExtractParameter("ExcludeTemplatesForDisplay", value).Trim();
this.IncludeBaseTemplatesForSelection = StringUtil.ExtractParameter("IncludeBaseTemplatesForSelection", value).Trim();
var queryItem = contextItem.Axes.SelectSingleItem(datasourceValue.Substring("query:".Length));
if (queryItem != null)
{
base.Source = queryItem.ID.ToString();
}
}
else if (value.StartsWith("query:"))
{
var queryItem = contextItem.Axes.SelectSingleItem(value.Substring("query:".Length));
if (queryItem != null)
{
base.Source = queryItem.ID.ToString();
}
}
else
{
base.Source = value;
}
}
}
}
/// <summary>
/// Overrides the <see cref="DropDown"/>, and changing the DataTreeView to use a FilteredTreeView
/// </summary>
protected override void DropDown()
{
base.DropDown();
if (!string.IsNullOrEmpty(this.Value))
{
var dataContext = Sitecore.Context.ClientPage.FindSubControl(this.DataContext) as DataContext;
Assert.IsNotNull(dataContext, typeof(DataContext), "Datacontext \"{0}\" not found.", (object)this.DataContext);
dataContext.Folder = this.Value;
}
var hiddenHolder = UIUtil.GetHiddenHolder(this);
DataTreeNode dataTreeNode = null;
var scrollbox = new Scrollbox();
Sitecore.Context.ClientPage.AddControl(hiddenHolder, scrollbox);
scrollbox.Width = 300;
scrollbox.Height = 400;
var dataTreeview = this.GetDataTreeview();
dataTreeview.Class = "scTreeview scPopupTree";
dataTreeview.DataContext = this.DataContext;
dataTreeview.ID = this.ID + "_treeview";
dataTreeview.AllowDragging = false;
if (this.AllowNone)
{
dataTreeNode = new DataTreeNode();
Sitecore.Context.ClientPage.AddControl(dataTreeview, dataTreeNode);
dataTreeNode.ID = this.ID + "_none";
dataTreeNode.Header = Translate.Text("[none]");
dataTreeNode.Expandable = false;
dataTreeNode.Expanded = false;
dataTreeNode.Value = "none";
dataTreeNode.Icon = "Applications/16x16/forbidden.png";
}
Sitecore.Context.ClientPage.AddControl(scrollbox, dataTreeview);
dataTreeview.Width = new Unit(100.0, UnitType.Percentage);
dataTreeview.Click = this.ID + ".Select";
dataTreeview.DataContext = this.DataContext;
if (string.IsNullOrEmpty(this.Value) && dataTreeNode != null)
{
dataTreeview.ClearSelection();
dataTreeNode.Selected = true;
}
SheerResponse.ShowPopup(this.ID, "below-right", scrollbox);
}
protected virtual DataTreeview GetDataTreeview()
{
return new FilteredDataTreeView
{
ExcludeTemplatesForDisplay = Tree.GetValues(this.ExcludeTemplatesForDisplay),
ExcludeTemplatesForSelection = Tree.GetValues(this.ExcludeTemplatesForSelection),
IncludeTemplatesForDisplay = Tree.GetValues(this.IncludeTemplatesForDisplay),
IncludeTemplatesForSelection = Tree.GetValues(this.IncludeTemplatesForSelection),
IncludeBaseTemplatesForSelection = Tree.GetValues(this.IncludeBaseTemplatesForSelection)
};
}
private static string[] GetValues(string templates)
{
if (String.IsNullOrEmpty(templates))
{
return null;
}
return templates.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
}
}
namespace Sitecore.Foundation.SitecoreExtensions.FieldTypes
{
using System;
using System.ComponentModel;
using System.Linq;
using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Foundation.SitecoreExtensions.Extensions;
using Sitecore.Globalization;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
using Sitecore.Web.UI.WebControls;
/// <summary>
/// Extends the <see cref="Sitecore.Shell.Applications.ContentEditor.TreeList"/> by
/// adding in support to filter the selectable templates in a Tree by the base templates
/// Syntax for the Field Source: Datasource={Insert Sitecore Query or Item Path}&IncludeBaseTemplatesForSelection={Insert GUID}
/// </summary>
public class TreeList : Sitecore.Shell.Applications.ContentEditor.TreeList
{
#region Additional Fields for Filtering
[Category("Data")]
[Description("Comma separated list of item ids.")]
public string IncludeBaseTemplatesForSelection
{
get
{
return this.GetViewStateString("IncludeBaseTemplatesForSelection");
}
set
{
Assert.ArgumentNotNull(value, "value");
this.SetViewStateString("IncludeBaseTemplatesForSelection", value);
}
}
#endregion
/// <summary>
/// Overrides the source property to pull out DataSource property
/// </summary>
public new string Source
{
get
{
return base.Source;
}
set
{
if (value == null)
{
base.Source = null;
}
else
{
var datasourceValue = StringUtil.ExtractParameter("DataSource", value).Trim();
if (datasourceValue.StartsWith("query:"))
{
base.Source = value.Replace(datasourceValue, this.ResolveQuery(datasourceValue));
}
else if (value.StartsWith("query:"))
{
base.Source = this.ResolveQuery(value);
}
else
{
base.Source = value;
}
}
}
}
/// <summary>
/// Overrides the <see cref="OnLoad"/> method to set our custom properties
/// </summary>
/// <param name="args"></param>
protected override void OnLoad(EventArgs args)
{
if (!Sitecore.Context.ClientPage.IsEvent)
{
this.SetProperties();
}
base.OnLoad(args);
}
/// <summary>
/// Overrides the <see cref="Add"/> method to execute our custom logic
/// and determine if the selected item in the tree inherits from
/// a configured base template
/// </summary>
protected new void Add()
{
if (this.Disabled)
{
return;
}
var viewStateString = this.GetViewStateString("ID");
var treeviewEx = this.FindControl(viewStateString + "_all") as TreeviewEx;
Assert.IsNotNull(treeviewEx, typeof(DataTreeview));
var listbox = this.FindControl(viewStateString + "_selected") as Listbox;
Assert.IsNotNull(listbox, typeof(Listbox));
var selectionItem = treeviewEx.GetSelectionItem(Language.Parse(this.ItemLanguage), Sitecore.Data.Version.Latest);
if (selectionItem == null)
{
SheerResponse.Alert("Select an item in the Content Tree.");
}
else
{
if (!this.HasIncludeBaseTemplatesForSelection(selectionItem))
{
return;
}
base.Add();
}
}
/// <summary>
/// Resolves the Sitecore Query
/// </summary>
/// <param name="query">The Sitecore Query</param>
/// <returns></returns>
protected virtual string ResolveQuery(string query)
{
var contextItem = Sitecore.Context.ContentDatabase.Items[this.ItemID];
/**
* This area can be an additional extension point to allow for 'tokens'
* within the query, such as $site or $home.
*/
var obj = contextItem?.Axes.SelectSingleItem(query.Substring("query:".Length));
return obj != null
? obj.Paths.FullPath
: String.Empty;
}
private void SetProperties()
{
this.IncludeBaseTemplatesForSelection = StringUtil.ExtractParameter("IncludeBaseTemplatesForSelection", this.Source).Trim();
}
private bool HasIncludeBaseTemplatesForSelection(Item item)
{
if (String.IsNullOrEmpty(this.IncludeBaseTemplatesForSelection))
{
return true;
}
var items = this.IncludeBaseTemplatesForSelection.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (!items.Any())
{
return true;
}
return items.Any(id => item.IsDerived(new ID(id)));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment