From 84171c6b98249d6e322ea3f0800bba57d4b8981f Mon Sep 17 00:00:00 2001 From: Hendy Date: Fri, 1 Mar 2013 22:53:14 +0000 Subject: [PATCH] Added Media and Member support to XPath CheckBoxList --- .../XPathCheckBoxListDataEditor.cs | 284 ++++++++------- .../XPathCheckBoxListOptions.cs | 106 ++++-- .../XPathCheckBoxListPreValueEditor.cs | 342 ++++++++++-------- 3 files changed, 409 insertions(+), 323 deletions(-) diff --git a/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListDataEditor.cs b/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListDataEditor.cs index 5ef6c8f343..7dd97d2196 100644 --- a/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListDataEditor.cs +++ b/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListDataEditor.cs @@ -8,151 +8,171 @@ using umbraco.interfaces; namespace umbraco.editorControls.XPathCheckBoxList { - /// - /// Renders a CheckBoxList using with option nodes obtained by an XPath expression - /// - public class XPathCheckBoxListDataEditor : CompositeControl, IDataEditor - { - /// - /// Field for the data. - /// - private IData data; + /// + /// Renders a CheckBoxList using with option nodes obtained by an XPath expression + /// + public class XPathCheckBoxListDataEditor : CompositeControl, IDataEditor + { + /// + /// Field for the data. + /// + private IData data; - /// - /// Field for the options. - /// - private XPathCheckBoxListOptions options; + /// + /// Field for the options. + /// + private XPathCheckBoxListOptions options; - /// - /// Field for the checkbox list. - /// - private CheckBoxList checkBoxList = new CheckBoxList(); + /// + /// Field for the checkbox list. + /// + private CheckBoxList checkBoxList = new CheckBoxList(); - /// - /// Gets a value indicating whether [treat as rich text editor]. - /// - /// - /// true if [treat as rich text editor]; otherwise, false. - /// - public virtual bool TreatAsRichTextEditor - { - get - { - return false; - } - } + /// + /// Gets a value indicating whether [treat as rich text editor]. + /// + /// + /// true if [treat as rich text editor]; otherwise, false. + /// + public virtual bool TreatAsRichTextEditor + { + get + { + return false; + } + } - /// - /// Gets a value indicating whether [show label]. - /// - /// true if [show label]; otherwise, false. - public virtual bool ShowLabel - { - get - { - return true; - } - } + /// + /// Gets a value indicating whether [show label]. + /// + /// true if [show label]; otherwise, false. + public virtual bool ShowLabel + { + get + { + return true; + } + } - /// - /// Gets the editor. - /// - /// The editor. - public Control Editor - { - get - { - return this; - } - } + /// + /// Gets the editor. + /// + /// The editor. + public Control Editor + { + get + { + return this; + } + } - /// - /// Initializes a new instance of XPathCheckBoxListDataEditor - /// - /// - /// - internal XPathCheckBoxListDataEditor(IData data, XPathCheckBoxListOptions options) - { - this.data = data; - this.options = options; - } + /// + /// Initializes a new instance of XPathCheckBoxListDataEditor + /// + /// + /// + internal XPathCheckBoxListDataEditor(IData data, XPathCheckBoxListOptions options) + { + this.data = data; + this.options = options; + } - /// - /// 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. - /// - 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(); + /// + /// 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. + /// + protected override void CreateChildControls() + { + switch (this.options.UmbracoObjectType) + { + case uQuery.UmbracoObjectType.Unknown: + case uQuery.UmbracoObjectType.Document: - this.Controls.Add(this.checkBoxList); - } + this.checkBoxList.DataSource = uQuery.GetNodesByXPath(this.options.XPath).Where(x => x.Id != -1).ToNameIds(); + break; - /// - /// Raises the event. - /// - /// The object that contains the event data. - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); - this.EnsureChildControls(); + case uQuery.UmbracoObjectType.Media: - if (!this.Page.IsPostBack && this.data.Value != null) - { - string value = this.data.Value.ToString(); - List selectedValues = new List(); + this.checkBoxList.DataSource = uQuery.GetMediaByXPath(this.options.XPath).Where(x => x.Id != -1).ToNameIds(); + break; - 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(); - } + case uQuery.UmbracoObjectType.Member: - // 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; - } - } - } - } + this.checkBoxList.DataSource = uQuery.GetMembersByXPath(this.options.XPath).ToNameIds(); + break; + } - /// - /// Called by Umbraco when saving the node - /// - public void Save() - { - // Get all checked item values - IEnumerable selectedOptions = from ListItem item in this.checkBoxList.Items - where item.Selected - select item.Value; + this.checkBoxList.DataTextField = "Value"; + this.checkBoxList.DataValueField = this.options.UseIds ? "Key" : "Value"; + this.checkBoxList.DataBind(); - if (this.options.UseXml) - { - string elementName = this.options.UseIds ? "nodeId" : "nodeName"; + this.Controls.Add(this.checkBoxList); + } - 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()); - } - } - } + /// + /// Raises the event. + /// + /// The object that contains the event data. + 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 selectedValues = new List(); + + 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; + } + } + } + } + + /// + /// Called by Umbraco when saving the node + /// + public void Save() + { + // Get all checked item values + IEnumerable 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()); + } + } + } } diff --git a/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListOptions.cs b/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListOptions.cs index 7c8905d912..374951cf66 100644 --- a/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListOptions.cs +++ b/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListOptions.cs @@ -1,45 +1,77 @@ -using System.ComponentModel; -using umbraco.cms.businesslogic.datatype; +using System; +using System.ComponentModel; namespace umbraco.editorControls.XPathCheckBoxList { - /// - /// Data Class, used to store the configuration options for the XPathCheckBoxListPreValueEditor - /// - public class XPathCheckBoxListOptions : AbstractOptions - { - /// - /// Initializes a new instance of the class. - /// - public XPathCheckBoxListOptions() - { - } - /// - /// Initializes a new instance of the class. - /// - /// if set to true [load defaults]. - public XPathCheckBoxListOptions(bool loadDefaults) - : base(loadDefaults) - { - } + /// + /// DataType configuration options for the XPath CheckBoxList + /// + public class XPathCheckBoxListOptions : AbstractOptions + { + /// + /// string guid for either a node, media or member + /// + private string type = null; - /// - /// XPath string used to get Nodes to be used as CheckBox options in a CheckBoxList - /// - [DefaultValue("")] - public string XPath { get; set; } + /// + /// Initializes a new instance of the class. + /// + public XPathCheckBoxListOptions() + : base(true) + { + } - /// - /// Defaults to true, where the property value will be stored as an Xml Fragment, else if false, a Csv will be stored - /// - [DefaultValue(true)] - public bool UseXml { get; set; } + /// + /// Gets or sets the guid as a string representing either a Document, Media or Member + /// + public string Type + { + get + { + // null check for the type, as older versions of this data type won't have this value stored + if (this.type == null) + { + return uQuery.UmbracoObjectType.Document.GetGuid().ToString(); + } - /// - /// Defaults to true, where property value stored is NodeIds, else if false, then value stored is the Node Names - /// - [DefaultValue(true)] - public bool UseIds { get; set; } - } + return this.type; + } + + set + { + this.type = value; + } + } + + /// + /// Gets or sets the XPath string used to get the Nodes, Media or Members + /// + [DefaultValue("//*")] + public string XPath { get; set; } + + /// + /// Defaults to true, where the property value will be stored as an Xml Fragment, else if false, a Csv will be stored + /// + [DefaultValue(true)] + public bool UseXml { get; set; } + + /// + /// Defaults to true, where property value stored is NodeIds, else if false, then value stored is the Node Names + /// + [DefaultValue(true)] + public bool UseIds { get; set; } + + /// + /// Gets the UmbracoObjectType from the stored string guid + /// + /// a Document, Media or Member + public uQuery.UmbracoObjectType UmbracoObjectType + { + get + { + return uQuery.GetUmbracoObjectType(new Guid(this.Type)); + } + } + } } \ No newline at end of file diff --git a/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListPreValueEditor.cs b/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListPreValueEditor.cs index 2064ff818b..6d528b32c0 100644 --- a/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListPreValueEditor.cs +++ b/src/umbraco.editorControls/XPathCheckBoxList/XPathCheckBoxListPreValueEditor.cs @@ -7,183 +7,217 @@ using System.Linq; namespace umbraco.editorControls.XPathCheckBoxList { - /// - /// 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 - /// - class XPathCheckBoxListPreValueEditor : AbstractJsonPrevalueEditor - { - /// - /// DropDownList for specifying the database column type. - /// - private DropDownList dbTypeDropDownList = new DropDownList(); + /// + /// 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 + /// + class XPathCheckBoxListPreValueEditor : AbstractJsonPrevalueEditor + { + /// + /// Radio buttons to select type of node to pick from: Content / Media / Members + /// + private RadioButtonList typeRadioButtonList = new RadioButtonList(); - /// - /// TextBox control to get the XPath expression - /// - private TextBox xPathTextBox = new TextBox(); + /// + /// TextBox control to get the XPath expression + /// + private TextBox xPathTextBox = new TextBox(); - /// - /// RequiredFieldValidator to ensure an XPath expression has been entered - /// - private RequiredFieldValidator xPathRequiredFieldValidator = new RequiredFieldValidator(); + /// + /// RequiredFieldValidator to ensure an XPath expression has been entered + /// + private RequiredFieldValidator xPathRequiredFieldValidator = new RequiredFieldValidator(); - /// - /// Server side validation of XPath expression, to ensure some nodes are returned - /// - private CustomValidator xPathCustomValidator = new CustomValidator(); + /// + /// Server side validation of XPath expression + /// + private CustomValidator xPathCustomValidator = new CustomValidator(); - /// - /// Store an Xml fragment or a Csv - /// - private RadioButtonList storageTypeRadioButtonList = new RadioButtonList() { RepeatDirection = RepeatDirection.Vertical, RepeatLayout = RepeatLayout.Flow }; + /// + /// Store an Xml fragment or a Csv + /// + private RadioButtonList storageTypeRadioButtonList = new RadioButtonList() { RepeatDirection = RepeatDirection.Vertical, RepeatLayout = RepeatLayout.Flow }; - /// - /// Select Node IDs or Node Names as the values to store - /// - private DropDownList valueTypeDropDownList = new DropDownList(); + /// + /// Select Node IDs or Node Names as the values to store + /// + private DropDownList valueTypeDropDownList = new DropDownList(); - /// - /// Data object used to define the configuration status of this PreValueEditor - /// - private XPathCheckBoxListOptions options = null; + /// + /// Data object used to define the configuration status of this PreValueEditor + /// + private XPathCheckBoxListOptions options = null; - /// - /// Gets the options data object that represents the current state of this datatypes configuration - /// - internal XPathCheckBoxListOptions Options - { - get - { - if (this.options == null) - { - // Deserialize any stored settings for this PreValueEditor instance - this.options = this.GetPreValueOptions(); + /// + /// Gets the options data object that represents the current state of this datatypes configuration + /// + internal XPathCheckBoxListOptions Options + { + get + { + if (this.options == null) + { + // Deserialize any stored settings for this PreValueEditor instance + this.options = this.GetPreValueOptions(); - // 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(true); - } - } - return this.options; - } - } + // 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(); + } + } - /// - /// Initialize a new instance of XPathCheckBoxlistPreValueEditor - /// - /// XPathCheckBoxListDataType + return this.options; + } + } + + /// + /// Initialize a new instance of XPathCheckBoxlistPreValueEditor + /// + /// XPathCheckBoxListDataType public XPathCheckBoxListPreValueEditor(umbraco.cms.businesslogic.datatype.BaseDataType dataType) - : base(dataType) - { - } + : base(dataType, cms.businesslogic.datatype.DBTypes.Ntext) + { + } - /// - /// Creates all of the controls and assigns all of their properties - /// - protected override void CreateChildControls() - { - this.xPathTextBox.ID = "xPathTextBox"; - this.xPathTextBox.CssClass = "umbEditorTextField"; + /// + /// Creates all of the controls and assigns all of their properties + /// + protected override void CreateChildControls() + { + //radio buttons to select type of nodes that can be picked (Document, Media or Member) + this.typeRadioButtonList.Items.Add(new ListItem(uQuery.UmbracoObjectType.Document.GetFriendlyName(), uQuery.UmbracoObjectType.Document.GetGuid().ToString())); + this.typeRadioButtonList.Items.Add(new ListItem(uQuery.UmbracoObjectType.Media.GetFriendlyName(), uQuery.UmbracoObjectType.Media.GetGuid().ToString())); + this.typeRadioButtonList.Items.Add(new ListItem(uQuery.UmbracoObjectType.Member.GetFriendlyName(), uQuery.UmbracoObjectType.Member.GetGuid().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.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.xPathCustomValidator.ControlToValidate = this.xPathTextBox.ID; + this.xPathCustomValidator.Display = ValidatorDisplay.Dynamic; + this.xPathCustomValidator.ServerValidate += new ServerValidateEventHandler(this.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.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.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); - } + this.Controls.AddPrevalueControls( + this.typeRadioButtonList, + this.xPathTextBox, + this.xPathRequiredFieldValidator, + this.xPathCustomValidator, + this.storageTypeRadioButtonList, + this.valueTypeDropDownList); + } - /// - /// - /// - /// - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); + /// + /// Raises the event. + /// + /// The object that contains the event data. + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); - // Read in stored configuration values - this.xPathTextBox.Text = this.Options.XPath; - this.storageTypeRadioButtonList.SelectedValue = this.Options.UseXml.ToString(); - this.valueTypeDropDownList.SelectedValue = this.Options.UseIds.ToString(); - } + // Read in stored configuration values + this.typeRadioButtonList.SelectedValue = this.Options.Type; + this.xPathTextBox.Text = this.Options.XPath; + this.storageTypeRadioButtonList.SelectedValue = this.Options.UseXml.ToString(); + this.valueTypeDropDownList.SelectedValue = this.Options.UseIds.ToString(); + } - /// - /// Will run the entered XPath expression to ensure it's valid - /// - /// xPathCustomValidator - /// - private void XPathCustomValidator_ServerValidate(object source, ServerValidateEventArgs args) - { - string xPath = args.Value; - bool isValid = false; + /// + /// Will run the entered XPath expression to ensure it's valid + /// + /// xPathCustomValidator + /// + 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"; - } + try + { + switch (this.options.UmbracoObjectType) + { + case uQuery.UmbracoObjectType.Document: + if (uQuery.GetNodesByXPath(xPath).Count() >= 0) + { + isValid = true; + } - args.IsValid = isValid; - } + break; - /// - /// Saves the pre value data to Umbraco - /// - public override void Save() - { - if (this.Page.IsValid) - { - // always use NText - base.m_DataType.DBType = cms.businesslogic.datatype.DBTypes.Ntext; + case uQuery.UmbracoObjectType.Media: + if (uQuery.GetMediaByXPath(xPath).Count() >= 0) + { + isValid = true; + } - this.Options.XPath = this.xPathTextBox.Text; - this.Options.UseXml = bool.Parse(this.storageTypeRadioButtonList.SelectedValue); - this.Options.UseIds = bool.Parse(this.valueTypeDropDownList.SelectedValue); + break; - this.SaveAsJson(this.Options); // Serialize to Umbraco database field - } - } + case uQuery.UmbracoObjectType.Member: + if (uQuery.GetMembersByXPath(xPath).Count() >= 0) + { + isValid = true; + } - /// - /// Replaces the base class writer and instead uses the shared uComponents extension method, to inject consistant markup - /// - /// - protected override void RenderContents(HtmlTextWriter writer) - { - //writer.AddPrevalueRow("Database Type", this.dbTypeDropDownList); - writer.AddPrevalueRow("XPath Expression", @"can use the tokens $ancestorOrSelf, $parentPage and $currentPage, eg.
-
- all siblings: $parentPage//*[@id != $currentPage/@id]
- ", this.xPathTextBox, this.xPathRequiredFieldValidator, this.xPathCustomValidator); - writer.AddPrevalueRow("Storage Type", this.storageTypeRadioButtonList); - writer.AddPrevalueRow("Values", this.valueTypeDropDownList); - } - } + break; + } + } + catch (XPathException) + { + this.xPathCustomValidator.ErrorMessage = " Syntax error in XPath expression"; + } + + args.IsValid = isValid; + } + + /// + /// Saves the pre value data to Umbraco + /// + public override void Save() + { + if (this.Page.IsValid) + { + this.Options.Type = this.typeRadioButtonList.SelectedValue; + 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 + } + } + + /// + /// Replaces the base class writer and instead uses the shared uComponents extension method, to inject consistant markup + /// + /// + protected override void RenderContents(HtmlTextWriter writer) + { + writer.AddPrevalueRow( + "Type", + "the xml schema to query", + this.typeRadioButtonList); + + writer.AddPrevalueRow( + "XPath Expression", + "can use the tokens $ancestorOrSelf, $parentPage and $currentPage", + this.xPathTextBox, + this.xPathRequiredFieldValidator, + this.xPathCustomValidator); + + writer.AddPrevalueRow("Storage Type", this.storageTypeRadioButtonList); + writer.AddPrevalueRow("Values", this.valueTypeDropDownList); + } + } }