uComponents: Added XPathCheckBoxList to the core
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Xml.Linq;
|
||||
// using uComponents.Core;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace umbraco.editorControls.XPathCheckBoxList
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders a CheckBoxList using with option nodes obtained by an XPath expression
|
||||
/// </summary>
|
||||
public class XPathCheckBoxListDataEditor : CompositeControl, IDataEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Field for the data.
|
||||
/// </summary>
|
||||
private IData data;
|
||||
|
||||
/// <summary>
|
||||
/// Field for the options.
|
||||
/// </summary>
|
||||
private XPathCheckBoxListOptions options;
|
||||
|
||||
/// <summary>
|
||||
/// Field for the checkbox list.
|
||||
/// </summary>
|
||||
private CheckBoxList checkBoxList = new CheckBoxList();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether [treat as rich text editor].
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if [treat as rich text editor]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public virtual bool TreatAsRichTextEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether [show label].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [show label]; otherwise, <c>false</c>.</value>
|
||||
public virtual bool ShowLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the editor.
|
||||
/// </summary>
|
||||
/// <value>The editor.</value>
|
||||
public Control Editor
|
||||
{
|
||||
get
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of XPathCheckBoxListDataEditor
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="options"></param>
|
||||
internal XPathCheckBoxListDataEditor(IData data, XPathCheckBoxListOptions options)
|
||||
{
|
||||
this.data = data;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
|
||||
/// </summary>
|
||||
protected override void CreateChildControls()
|
||||
{
|
||||
this.checkBoxList.DataSource = uQuery.GetNodesByXPath(this.options.XPath).ToNameIds();
|
||||
this.checkBoxList.DataTextField = "Value";
|
||||
this.checkBoxList.DataValueField = this.options.UseIds ? "Key" : "Value";
|
||||
this.checkBoxList.DataBind();
|
||||
|
||||
this.Controls.Add(this.checkBoxList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Web.UI.Control.Load"/> event.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
this.EnsureChildControls();
|
||||
|
||||
if (!this.Page.IsPostBack && this.data.Value != null)
|
||||
{
|
||||
string value = this.data.Value.ToString();
|
||||
List<string> selectedValues = new List<string>();
|
||||
|
||||
if (xmlHelper.CouldItBeXml(value))
|
||||
{
|
||||
// build selected values from XML fragment
|
||||
foreach (XElement nodeXElement in XElement.Parse(value).Elements())
|
||||
{
|
||||
selectedValues.Add(nodeXElement.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume a CSV source
|
||||
selectedValues = value.Split(',').ToList();
|
||||
}
|
||||
|
||||
// Find checkboxes where values match the stored values and set to selected
|
||||
ListItem checkBoxListItem = null;
|
||||
foreach (string selectedValue in selectedValues)
|
||||
{
|
||||
checkBoxListItem = this.checkBoxList.Items.FindByValue(selectedValue);
|
||||
if (checkBoxListItem != null)
|
||||
{
|
||||
checkBoxListItem.Selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by Umbraco when saving the node
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
// Get all checked item values
|
||||
IEnumerable<string> selectedOptions = from ListItem item in this.checkBoxList.Items
|
||||
where item.Selected
|
||||
select item.Value;
|
||||
|
||||
if (this.options.UseXml)
|
||||
{
|
||||
string elementName = this.options.UseIds ? "nodeId" : "nodeName";
|
||||
|
||||
this.data.Value = new XElement("XPathCheckBoxList",
|
||||
selectedOptions.Select(x => new XElement(elementName, x.ToString()))).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save the CSV
|
||||
this.data.Value = string.Join(",", selectedOptions.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using umbraco.cms.businesslogic.datatype;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace umbraco.editorControls.XPathCheckBoxList
|
||||
{
|
||||
/// <summary>
|
||||
/// This datatype will render a CheckBoxList where the options are defined by an XPath expression,
|
||||
/// </summary>
|
||||
public class XPathCheckBoxListDataType : umbraco.cms.businesslogic.datatype.BaseDataType, IDataType
|
||||
{
|
||||
/// <summary>
|
||||
/// Field for the preValueEditor.
|
||||
/// </summary>
|
||||
private XPathCheckBoxListPreValueEditor preValueEditor;
|
||||
|
||||
/// <summary>
|
||||
/// Field for the dataEditor.
|
||||
/// </summary>
|
||||
private IDataEditor dataEditor;
|
||||
|
||||
/// <summary>
|
||||
/// Field for the data.
|
||||
/// </summary>
|
||||
private IData data;
|
||||
|
||||
/// <summary>
|
||||
/// Field for the options.
|
||||
/// </summary>
|
||||
private XPathCheckBoxListOptions options;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the options.
|
||||
/// </summary>
|
||||
/// <value>The options.</value>
|
||||
public XPathCheckBoxListOptions Options
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.options == null)
|
||||
{
|
||||
this.options = ((XPathCheckBoxListPreValueEditor)this.PrevalueEditor).Options;
|
||||
}
|
||||
|
||||
return this.options;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the data type.
|
||||
/// </summary>
|
||||
/// <value>The name of the data type.</value>
|
||||
public override string DataTypeName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "XPath CheckBoxList";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
public override Guid Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Guid(DataTypeGuids.XPathCheckBoxListId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lazy load the associated PreValueEditor instance,
|
||||
/// this is constructed supplying 'this'
|
||||
/// </summary>
|
||||
public override IDataPrevalue PrevalueEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.preValueEditor == null)
|
||||
{
|
||||
this.preValueEditor = new XPathCheckBoxListPreValueEditor(this);
|
||||
}
|
||||
|
||||
return this.preValueEditor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lazy load the assocated DataEditor,
|
||||
/// this is constructed supplying the data value stored by the PreValueEditor, and also the configuration settings of the PreValueEditor
|
||||
/// </summary>
|
||||
public override IDataEditor DataEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.dataEditor == null)
|
||||
{
|
||||
this.dataEditor = new XPathCheckBoxListDataEditor(this.Data, this.Options);
|
||||
}
|
||||
|
||||
return this.dataEditor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lazy load an empty DefaultData object, this is used to pass data between the PreValueEditor and the DataEditor
|
||||
/// </summary>
|
||||
public override IData Data
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.data == null)
|
||||
{
|
||||
if (((XPathCheckBoxListPreValueEditor)this.PrevalueEditor).Options.UseXml)
|
||||
{
|
||||
// Storing an Xml fragment
|
||||
this.data = new XmlData(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Storing a Csv
|
||||
this.data = new umbraco.cms.businesslogic.datatype.DefaultData(this);
|
||||
}
|
||||
}
|
||||
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.ComponentModel;
|
||||
using umbraco.cms.businesslogic.datatype;
|
||||
|
||||
namespace umbraco.editorControls.XPathCheckBoxList
|
||||
{
|
||||
/// <summary>
|
||||
/// Data Class, used to store the configuration options for the XPathCheckBoxListPreValueEditor
|
||||
/// </summary>
|
||||
public class XPathCheckBoxListOptions : AbstractOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="XPathCheckBoxListOptions"/> class.
|
||||
/// </summary>
|
||||
public XPathCheckBoxListOptions()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="XPathCheckBoxListOptions"/> class.
|
||||
/// </summary>
|
||||
/// <param name="loadDefaults">if set to <c>true</c> [load defaults].</param>
|
||||
public XPathCheckBoxListOptions(bool loadDefaults)
|
||||
: base(loadDefaults)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// XPath string used to get Nodes to be used as CheckBox options in a CheckBoxList
|
||||
/// </summary>
|
||||
[DefaultValue("")]
|
||||
public string XPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defaults to true, where the property value will be stored as an Xml Fragment, else if false, a Csv will be stored
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool UseXml { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defaults to true, where property value stored is NodeIds, else if false, then value stored is the Node Names
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
public bool UseIds { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Xml.XPath;
|
||||
// using uComponents.DataTypes.Shared.Extensions;
|
||||
// using uComponents.DataTypes.Shared.PrevalueEditors;
|
||||
using umbraco.cms.businesslogic.datatype;
|
||||
|
||||
namespace umbraco.editorControls.XPathCheckBoxList
|
||||
{
|
||||
/// <summary>
|
||||
/// This PreValueEditor will require an XPath expression to define the nodes to pick as CheckBox options,
|
||||
/// TODO: [HR] min / max selections ?
|
||||
/// Uses the shared JsonPreValueEditor as nice way of lightweight serializing a config data class object into a single DB field
|
||||
/// </summary>
|
||||
class XPathCheckBoxListPreValueEditor : AbstractJsonPrevalueEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// DropDownList for specifying the database column type.
|
||||
/// </summary>
|
||||
private DropDownList dbTypeDropDownList = new DropDownList();
|
||||
|
||||
/// <summary>
|
||||
/// TextBox control to get the XPath expression
|
||||
/// </summary>
|
||||
private TextBox xPathTextBox = new TextBox();
|
||||
|
||||
/// <summary>
|
||||
/// RequiredFieldValidator to ensure an XPath expression has been entered
|
||||
/// </summary>
|
||||
private RequiredFieldValidator xPathRequiredFieldValidator = new RequiredFieldValidator();
|
||||
|
||||
/// <summary>
|
||||
/// Server side validation of XPath expression, to ensure some nodes are returned
|
||||
/// </summary>
|
||||
private CustomValidator xPathCustomValidator = new CustomValidator();
|
||||
|
||||
/// <summary>
|
||||
/// Store an Xml fragment or a Csv
|
||||
/// </summary>
|
||||
private RadioButtonList storageTypeRadioButtonList = new RadioButtonList() { RepeatDirection = RepeatDirection.Vertical, RepeatLayout = RepeatLayout.Flow };
|
||||
|
||||
/// <summary>
|
||||
/// Select Node IDs or Node Names as the values to store
|
||||
/// </summary>
|
||||
private DropDownList valueTypeDropDownList = new DropDownList();
|
||||
|
||||
/// <summary>
|
||||
/// Data object used to define the configuration status of this PreValueEditor
|
||||
/// </summary>
|
||||
private XPathCheckBoxListOptions options = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the options data object that represents the current state of this datatypes configuration
|
||||
/// </summary>
|
||||
internal XPathCheckBoxListOptions Options
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.options == null)
|
||||
{
|
||||
// Deserialize any stored settings for this PreValueEditor instance
|
||||
this.options = this.GetPreValueOptions<XPathCheckBoxListOptions>();
|
||||
|
||||
// If still null, ie, object couldn't be de-serialized from PreValue[0] string value
|
||||
if (this.options == null)
|
||||
{
|
||||
// Create a new Options data object with the default values
|
||||
this.options = new XPathCheckBoxListOptions();
|
||||
}
|
||||
}
|
||||
return this.options;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of XPathCheckBoxlistPreValueEditor
|
||||
/// </summary>
|
||||
/// <param name="dataType">XPathCheckBoxListDataType</param>
|
||||
public XPathCheckBoxListPreValueEditor(umbraco.cms.businesslogic.datatype.BaseDataType dataType)
|
||||
: base(dataType)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates all of the controls and assigns all of their properties
|
||||
/// </summary>
|
||||
protected override void CreateChildControls()
|
||||
{
|
||||
this.dbTypeDropDownList.ID = "dbTypeDropDownList";
|
||||
this.dbTypeDropDownList.Items.Add(new ListItem(DBTypes.Nvarchar.ToString()));
|
||||
this.dbTypeDropDownList.Items.Add(new ListItem(DBTypes.Ntext.ToString()));
|
||||
|
||||
this.xPathTextBox.ID = "xPathTextBox";
|
||||
this.xPathTextBox.CssClass = "umbEditorTextField";
|
||||
|
||||
this.xPathRequiredFieldValidator.ControlToValidate = this.xPathTextBox.ID;
|
||||
this.xPathRequiredFieldValidator.Display = ValidatorDisplay.Dynamic;
|
||||
this.xPathRequiredFieldValidator.ErrorMessage = " XPath expression required";
|
||||
|
||||
this.xPathCustomValidator.ControlToValidate = this.xPathTextBox.ID;
|
||||
this.xPathCustomValidator.Display = ValidatorDisplay.Dynamic;
|
||||
this.xPathCustomValidator.ServerValidate += new ServerValidateEventHandler(XPathCustomValidator_ServerValidate);
|
||||
|
||||
this.storageTypeRadioButtonList.ID = "storageTypeRadioButtonList";
|
||||
this.storageTypeRadioButtonList.Items.Add(new ListItem("Xml", bool.TrueString));
|
||||
this.storageTypeRadioButtonList.Items.Add(new ListItem("Csv", bool.FalseString));
|
||||
|
||||
this.valueTypeDropDownList.ID = "valueTypeDropDownList";
|
||||
this.valueTypeDropDownList.Items.Add(new ListItem("Node Ids", bool.TrueString));
|
||||
this.valueTypeDropDownList.Items.Add(new ListItem("Node Names", bool.FalseString));
|
||||
|
||||
this.Controls.AddPrevalueControls(
|
||||
this.dbTypeDropDownList,
|
||||
this.xPathTextBox,
|
||||
this.xPathRequiredFieldValidator,
|
||||
this.xPathCustomValidator,
|
||||
this.storageTypeRadioButtonList,
|
||||
this.valueTypeDropDownList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
// Read in stored configuration values
|
||||
this.dbTypeDropDownList.SelectedValue = base.m_DataType.DBType.ToString();
|
||||
this.xPathTextBox.Text = this.Options.XPath;
|
||||
this.storageTypeRadioButtonList.SelectedValue = this.Options.UseXml.ToString();
|
||||
this.valueTypeDropDownList.SelectedValue = this.Options.UseIds.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will run the entered XPath expression to ensure it's valid
|
||||
/// </summary>
|
||||
/// <param name="source">xPathCustomValidator</param>
|
||||
/// <param name="args"></param>
|
||||
private void XPathCustomValidator_ServerValidate(object source, ServerValidateEventArgs args)
|
||||
{
|
||||
string xPath = args.Value;
|
||||
bool isValid = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (uQuery.GetNodesByXPath(xPath).Count >= 0)
|
||||
{
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
catch (XPathException)
|
||||
{
|
||||
this.xPathCustomValidator.ErrorMessage = " Syntax error in XPath expression";
|
||||
}
|
||||
|
||||
args.IsValid = isValid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the pre value data to Umbraco
|
||||
/// </summary>
|
||||
public override void Save()
|
||||
{
|
||||
if (this.Page.IsValid)
|
||||
{
|
||||
base.m_DataType.DBType = (umbraco.cms.businesslogic.datatype.DBTypes)Enum.Parse(typeof(umbraco.cms.businesslogic.datatype.DBTypes), this.dbTypeDropDownList.SelectedValue, true);
|
||||
|
||||
this.Options.XPath = this.xPathTextBox.Text;
|
||||
this.Options.UseXml = bool.Parse(this.storageTypeRadioButtonList.SelectedValue);
|
||||
this.Options.UseIds = bool.Parse(this.valueTypeDropDownList.SelectedValue);
|
||||
|
||||
this.SaveAsJson(this.Options); // Serialize to Umbraco database field
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the base class writer and instead uses the shared uComponents extension method, to inject consistant markup
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
protected override void RenderContents(HtmlTextWriter writer)
|
||||
{
|
||||
writer.AddPrevalueRow("Database Type", this.dbTypeDropDownList);
|
||||
writer.AddPrevalueRow("XPath Expression", this.xPathTextBox, this.xPathRequiredFieldValidator, this.xPathCustomValidator);
|
||||
writer.AddPrevalueRow("Storage Type", this.storageTypeRadioButtonList);
|
||||
writer.AddPrevalueRow("Values", this.valueTypeDropDownList);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user