(
+ "SELECT nodeObjectType FROM umbracoNode WHERE id = @id",
+ uQuery.SqlHelper.CreateParameter("@id", this.CurrentContentId)));
+ }
+ }
+
+ /////// NOT CURRENTLY USED, BUT MIGHT BE USEFUL TO MARK BIDIRECTIONAL RELATIONS
+ ///////
+ /////// string to identify a particular instance of this datatype
+ ///////
+ ////private string InstanceIdentifier
+ ////{
+ //// get
+ //// {
+ //// Property pickerRelationsProperty = new Property(((DefaultData)this.data).PropertyId);
+ //// return "[" + pickerRelationsProperty.PropertyType.Id.ToString() + "]";
+ //// }
+ ////}
+
+ ///
+ /// Initializes a new instance of PickerRelationsDataEditor
+ ///
+ /// data stored by this instance of this datatype (not currently used)
+ /// configuration options for this datatype as set by the PreValueEditor
+ internal PickerRelationsDataEditor(IData data, PickerRelationsOptions options)
+ {
+ this.data = data;
+ this.options = options;
+ }
+
+ ///
+ /// Creates the child controls
+ ///
+ protected override void CreateChildControls()
+ {
+ this.statusLiteral.ID = "pickerRelations";
+ this.Controls.Add(this.statusLiteral); // displays if this datatype is valid in this context, and if so, which pickerProperty and relationtype it wires up
+ this.Controls.Add(this.jsLiteral);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ protected override void OnLoad(EventArgs e)
+ {
+ base.OnLoad(e);
+ this.EnsureChildControls();
+
+ this.statusLiteral.Text = "";
+
+ try
+ {
+ this.statusLiteral.Text += "Mapping: " + this.GetMappingDetails();
+ }
+ catch(Exception ex)
+ {
+ this.statusLiteral.Text += "Error: " + ex.Message;
+ }
+
+ this.statusLiteral.Text += "";
+
+ if (this.options.HideDataEditor)
+ {
+ this.jsLiteral.Text = @"
+ ";
+ }
+ }
+
+ ///
+ /// Called by Umbraco when saving the node, this datatype doens't do anythign here, but with an event handler instead,
+ /// as needs to know the saved values of a sibling pickerProperty
+ ///
+ public void Save()
+ {
+ }
+
+ ///
+ /// returns a string "Property '[propertyAlias]' with RelationType '[relationTypeName]"
+ ///
+ ///
+ private string GetMappingDetails()
+ {
+ string mappingDetails = string.Empty;
+
+ UmbracoContent currentContentNode = new UmbracoContent(this.CurrentContentId);
+ Property pickerProperty = currentContentNode.getProperty(this.options.PropertyAlias);
+
+ if (pickerProperty != null)
+ {
+ RelationType relationType = new RelationType(this.options.RelationTypeId); // Does it still exist ? TODO: check
+
+ if (this.IsContextUmbracoObjectTypeValid(this.CurrentContextObjectType, relationType))
+ {
+ mappingDetails = "Property '" + pickerProperty.PropertyType.Name + "' with " +
+ "Relation Type '" + relationType.Name + "'";
+
+ if(this.options.ReverseIndexing)
+ {
+ mappingDetails += " (Reverse Index)";
+ }
+ }
+ else
+ {
+ throw new Exception("Conflict with this Content Object Type and that expected by the Relation Type '" + relationType.Name + "'");
+ }
+ }
+ else
+ {
+ throw new Exception("Can't find a Property with the Alias '" + this.options.PropertyAlias + "'");
+ }
+
+ return mappingDetails;
+ }
+
+ ///
+ /// returns the UmbracoObjectType associated as defined by the supplied relation type, and if reverse indexing has been enabled
+ ///
+ /// associated RealationType
+ ///
+ public uQuery.UmbracoObjectType GetPickerUmbracoObjectType(RelationType relationType)
+ {
+ uQuery.UmbracoObjectType pickerUmbracoObjectType = uQuery.UmbracoObjectType.Unknown;
+
+ if (!relationType.Dual && this.options.ReverseIndexing)
+ {
+ pickerUmbracoObjectType = relationType.GetParentUmbracoObjectType();
+ }
+ else
+ {
+ pickerUmbracoObjectType = relationType.GetChildUmbracoObjectType();
+ }
+
+ return pickerUmbracoObjectType;
+ }
+
+ ///
+ /// Check to see if the content id side of the relation type is valid (doesn't check the node picker id side)
+ ///
+ /// Type of the content object (content/ media or member)
+ /// Type of the relation.
+ ///
+ /// true if [is content object type valid] [the specified content object type]; otherwise, false.
+ ///
+ public bool IsContextUmbracoObjectTypeValid(uQuery.UmbracoObjectType contextUmbracoObjectType, RelationType relationType)
+ {
+ bool isContextObjectTypeValid = false;
+
+ if (!relationType.Dual && this.options.ReverseIndexing)
+ {
+ // expects the current context to be the child in the relation
+ if (contextUmbracoObjectType == relationType.GetChildUmbracoObjectType())
+ {
+ isContextObjectTypeValid = true;
+ }
+ }
+ else
+ {
+ // expects the current context to be the parent in the relation
+ if (contextUmbracoObjectType == relationType.GetParentUmbracoObjectType())
+ {
+ isContextObjectTypeValid = true;
+ }
+ }
+
+ return isContextObjectTypeValid;
+ }
+
+ /////
+ ///// Insted of rendering the current name of this property, use a consistant label
+ /////
+ /////
+ //protected override void Render(HtmlTextWriter writer)
+ //{
+ // writer.WriteLine("");
+ // writer.WriteLine("");
+ // base.Render(writer);
+ // writer.WriteLine("
");
+ //}
+ }
+}
diff --git a/components/editorControls/PickerRelations/PickerRelationsDataType.cs b/components/editorControls/PickerRelations/PickerRelationsDataType.cs
new file mode 100644
index 0000000000..865c0a27a9
--- /dev/null
+++ b/components/editorControls/PickerRelations/PickerRelationsDataType.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Xml;
+
+using umbraco.cms.businesslogic.datatype;
+using umbraco.interfaces;
+
+namespace umbraco.editorControls.PickerRelations
+{
+ ///
+ /// This datatype will render a CheckBoxList where the options are defined by an XPath expression,
+ ///
+ public class PickerRelationsDataType : umbraco.cms.businesslogic.datatype.BaseDataType, IDataType
+ {
+ ///
+ ///
+ ///
+ private PickerRelationsPreValueEditor preValueEditor;
+
+ ///
+ ///
+ ///
+ private IDataEditor dataEditor;
+
+ ///
+ ///
+ ///
+ private IData data;
+
+ ///
+ /// Gets the name of the data type.
+ ///
+ /// The name of the data type.
+ public override string DataTypeName { get { return "Picker Relations"; } }
+
+ ///
+ /// Gets the id.
+ ///
+ /// The id.
+ public override Guid Id { get { return new Guid(DataTypeGuids.PickerRelationsId); } }
+
+ ///
+ /// Lazy load the associated PreValueEditor instance,
+ /// this is constructed supplying 'this'
+ ///
+ public override IDataPrevalue PrevalueEditor
+ {
+ get
+ {
+ if (this.preValueEditor == null)
+ {
+ this.preValueEditor = new PickerRelationsPreValueEditor(this);
+ }
+ return this.preValueEditor;
+ }
+ }
+
+ ///
+ /// Lazy load the assocated DataEditor,
+ /// this is constructed supplying the data value stored by the PreValueEditor, and also the configuration settings of the PreValueEditor
+ ///
+ public override IDataEditor DataEditor
+ {
+ get
+ {
+ if (this.dataEditor == null)
+ {
+ this.dataEditor = new PickerRelationsDataEditor(this.Data, ((PickerRelationsPreValueEditor)this.PrevalueEditor).Options);
+ }
+ return this.dataEditor;
+ }
+ }
+
+ ///
+ /// Lazy load an empty DefaultData object, this is used to pass data between the PreValueEditor and the DataEditor
+ ///
+ public override IData Data
+ {
+ get
+ {
+ if (this.data == null)
+ {
+ this.data = new umbraco.cms.businesslogic.datatype.DefaultData(this);
+ }
+ return this.data;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/editorControls/PickerRelations/PickerRelationsEventHandler.cs b/components/editorControls/PickerRelations/PickerRelationsEventHandler.cs
new file mode 100644
index 0000000000..f255d2a99f
--- /dev/null
+++ b/components/editorControls/PickerRelations/PickerRelationsEventHandler.cs
@@ -0,0 +1,267 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using umbraco.BusinessLogic; // ApplicationBase
+using umbraco.cms.businesslogic; // SaveEventArgs
+using umbraco.cms.businesslogic.media; // Media
+using umbraco.cms.businesslogic.member; // Member
+using umbraco.cms.businesslogic.web; // Documentusing umbraco.cms.businesslogic.propertytype;
+using umbraco.cms.businesslogic.property;
+using umbraco.cms.businesslogic.relation;
+using umbraco.DataLayer;
+
+namespace umbraco.editorControls.PickerRelations
+{
+ ///
+ /// Event handler that will convert a CSV into Relations
+ ///
+ public class PickerRelationsEventHandler : ApplicationBase
+ {
+ private enum PickerStorageFormat
+ {
+ Csv,
+ Xml
+ }
+
+ ///
+ /// Initializes a new instance of PickerRelationsEventHandler,
+ /// hooks into the after event of saving a Content node, Media item or a Member
+ ///
+ public PickerRelationsEventHandler()
+ {
+ Document.AfterSave += new Document.SaveEventHandler(this.AfterSave);
+ Media.AfterSave += new Media.SaveEventHandler(this.AfterSave);
+ Member.AfterSave += new Member.SaveEventHandler(this.AfterSave);
+
+ Document.BeforeDelete += new Document.DeleteEventHandler(this.BeforeDelete);
+ Media.BeforeDelete += new Media.DeleteEventHandler(this.BeforeDelete);
+ Member.BeforeDelete += new Member.DeleteEventHandler(this.BeforeDelete);
+ }
+
+
+ ///
+ /// Event after all properties have been saved
+ ///
+ ///
+ ///
+ private void AfterSave(Content sender, SaveEventArgs e)
+ {
+ Guid pickerRelationsId = new Guid(DataTypeGuids.PickerRelationsId);
+
+ // For each PickerRelations datatype
+ foreach (Property pickerRelationsProperty in from property in sender.GenericProperties
+ where property.PropertyType.DataTypeDefinition.DataType.Id == pickerRelationsId
+ select property)
+ {
+ // used to identify this datatype instance - relations created are marked with this in the comment field
+ string instanceIdentifier = "[\"PropertyTypeId\":" + pickerRelationsProperty.PropertyType.Id.ToString() + "]";
+
+ // get configuration options for datatype
+ PickerRelationsOptions options = ((PickerRelationsPreValueEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.PrevalueEditor).Options;
+
+ // find Picker source propertyAlias field on sender
+ Property pickerProperty = sender.getProperty(options.PropertyAlias);
+
+ if (pickerProperty != null)
+ {
+ // get relationType from options
+ RelationType relationType = RelationType.GetById(options.RelationTypeId);
+
+ if (relationType != null)
+ {
+ // validate: 1) check current type of sender matches that expected by the relationType, validation method is in the DataEditor
+ uQuery.UmbracoObjectType contextObjectType = uQuery.UmbracoObjectType.Unknown;
+ switch (sender.GetType().ToString())
+ {
+ case "umbraco.cms.businesslogic.web.Document": contextObjectType = uQuery.UmbracoObjectType.Document; break;
+ case "umbraco.cms.businesslogic.media.Media": contextObjectType = uQuery.UmbracoObjectType.Media; break;
+ case "umbraco.cms.businesslogic.member.Member": contextObjectType = uQuery.UmbracoObjectType.Member; break;
+ }
+
+ if (((PickerRelationsDataEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.DataEditor)
+ .IsContextUmbracoObjectTypeValid(contextObjectType, relationType))
+ {
+
+ uQuery.UmbracoObjectType pickerUmbracoObjectType = uQuery.UmbracoObjectType.Unknown;
+
+ // Get the object type expected by the associated relation type and if this datatype has been configures as a rever index
+ pickerUmbracoObjectType = ((PickerRelationsDataEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.DataEditor)
+ .GetPickerUmbracoObjectType(relationType);
+
+
+ // clear all exisitng relations (or look to see previous verion of sender to delete changes ?)
+ DeleteRelations(relationType, sender.Id, options.ReverseIndexing, instanceIdentifier);
+
+ string pickerPropertyValue = pickerProperty.Value.ToString();
+
+ var pickerStorageFormat = PickerStorageFormat.Csv; // Assume default of csv
+
+ if (xmlHelper.CouldItBeXml(pickerPropertyValue))
+ {
+ pickerStorageFormat = PickerStorageFormat.Xml;
+ }
+
+ // Creating instances of Documents / Media / Members ensures the IDs are of a valid type - be quicker to check with GetUmbracoObjectType(int)
+ Dictionary pickerItems = null;
+ switch (pickerUmbracoObjectType)
+ {
+ case uQuery.UmbracoObjectType.Document:
+ switch (pickerStorageFormat)
+ {
+ case PickerStorageFormat.Csv:
+ pickerItems = uQuery.GetDocumentsByCsv(pickerPropertyValue).ToNameIds();
+ break;
+ case PickerStorageFormat.Xml:
+ pickerItems = uQuery.GetDocumentsByXml(pickerPropertyValue).ToNameIds();
+ break;
+ }
+
+ break;
+ case uQuery.UmbracoObjectType.Media:
+ switch (pickerStorageFormat)
+ {
+ case PickerStorageFormat.Csv:
+ pickerItems = uQuery.GetMediaByCsv(pickerPropertyValue).ToNameIds();
+ break;
+ case PickerStorageFormat.Xml:
+ pickerItems = uQuery.GetMediaByXml(pickerPropertyValue).ToNameIds();
+ break;
+ }
+ break;
+ case uQuery.UmbracoObjectType.Member:
+ switch (pickerStorageFormat)
+ {
+ case PickerStorageFormat.Csv:
+ pickerItems = uQuery.GetMembersByCsv(pickerPropertyValue).ToNameIds();
+ break;
+ case PickerStorageFormat.Xml:
+ pickerItems = uQuery.GetMembersByXml(pickerPropertyValue).ToNameIds();
+ break;
+ }
+ break;
+ }
+ if (pickerItems != null)
+ {
+ foreach (KeyValuePair pickerItem in pickerItems)
+ {
+ CreateRelation(relationType, sender.Id, pickerItem.Key, options.ReverseIndexing, instanceIdentifier);
+ }
+ }
+ }
+ else
+ {
+ // Error: content object type invalid with relation type
+ }
+ }
+ else
+ {
+ // Error: relation type is null
+ }
+ }
+ else
+ {
+ // Error: pickerProperty alias not found
+ }
+ }
+ }
+
+ ///
+ /// Clears any existing relations when deleting a node with a PickerRelations datatype
+ ///
+ /// The sender.
+ /// The instance containing the event data.
+ private void BeforeDelete(Content sender, DeleteEventArgs e)
+ {
+ Guid pickerRelationsId = new Guid(DataTypeGuids.PickerRelationsId);
+
+ // Clean up any relations
+
+ // For each PickerRelations datatype
+ foreach (Property pickerRelationsProperty in from property in sender.GenericProperties
+ where property.PropertyType.DataTypeDefinition.DataType.Id == pickerRelationsId
+ select property)
+ {
+ // used to identify this datatype instance - relations created are marked with this in the comment field
+ string instanceIdentifier = "[\"PropertyTypeId\":" + pickerRelationsProperty.PropertyType.Id.ToString() + "]";
+
+ // get configuration options for datatype
+ PickerRelationsOptions options = ((PickerRelationsPreValueEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.PrevalueEditor).Options;
+
+ // get relationType from options
+ RelationType relationType = RelationType.GetById(options.RelationTypeId);
+
+ if (relationType != null)
+ {
+ // clear all exisitng relations
+ DeleteRelations(relationType, sender.Id, options.ReverseIndexing, instanceIdentifier);
+ }
+ }
+ }
+
+ ///
+ /// Delete all relations using the content node for a given RelationType
+ ///
+ ///
+ ///
+ ///
+ /// NOT USED ATM
+ private static void DeleteRelations(RelationType relationType, int contentNodeId, bool reverseIndexing, string instanceIdentifier)
+ {
+ //if relationType is bi-directional or a reverse index then we can't get at the relations via the API, so using SQL
+ string getRelationsSql = "SELECT id FROM umbracoRelation WHERE relType = " + relationType.Id.ToString() + " AND ";
+
+ if (reverseIndexing || relationType.Dual)
+ {
+ getRelationsSql += "childId = " + contentNodeId.ToString();
+ }
+ if (relationType.Dual) // need to return relations where content node id is used on both sides
+ {
+ getRelationsSql += " OR ";
+ }
+ if (!reverseIndexing || relationType.Dual)
+ {
+ getRelationsSql += "parentId = " + contentNodeId.ToString();
+ }
+
+ getRelationsSql += " AND comment = '" + instanceIdentifier + "'";
+
+ using (IRecordsReader relations = uQuery.SqlHelper.ExecuteReader(getRelationsSql))
+ {
+ //clear data
+ Relation relation;
+ if (relations.HasRecords)
+ {
+ while (relations.Read())
+ {
+ relation = new Relation(relations.GetInt("id"));
+
+ // TODO: [HR] check to see if an instance identifier is used
+ relation.Delete();
+ }
+ }
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ /// id sourced from the Content / Media / Member
+ /// id sourced from the Picker
+ /// if true, reverses the parentId and child Id
+ /// JSON string with id of Picker Relations property instance
+ private static void CreateRelation(RelationType relationType, int contentNodeId, int pickerNodeId, bool reverseIndexing, string instanceIdentifier)
+ {
+ if (reverseIndexing)
+ {
+ Relation.MakeNew(pickerNodeId, contentNodeId, relationType, instanceIdentifier);
+ }
+ else
+ {
+ Relation.MakeNew(contentNodeId, pickerNodeId, relationType, instanceIdentifier);
+ }
+ }
+ }
+}
diff --git a/components/editorControls/PickerRelations/PickerRelationsOptions.cs b/components/editorControls/PickerRelations/PickerRelationsOptions.cs
new file mode 100644
index 0000000000..f06221e5d8
--- /dev/null
+++ b/components/editorControls/PickerRelations/PickerRelationsOptions.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace umbraco.editorControls.PickerRelations
+{
+ ///
+ /// Data Class, used to store the configuration options for the PickerRelationsPreValueEditor
+ ///
+ internal class PickerRelationsOptions
+ {
+ ///
+ /// Alias of the pickerProperty to get a csv value of IDs from //TODO: a known format for xml fragments would be good too
+ ///
+ public string PropertyAlias { get; set; }
+
+ ///
+ /// The Id of the RelationType to use
+ ///
+ public int RelationTypeId { get; set; }
+
+ ///
+ /// only relevant with parent-child
+ ///
+ public bool ReverseIndexing { get; set; }
+
+ ///
+ /// if true then the property is hidden
+ ///
+ public bool HideDataEditor { get; set; }
+
+ ///
+ /// Initializes an instance of PickerRelationsOptions
+ ///
+ public PickerRelationsOptions()
+ {
+ // Default values
+ this.PropertyAlias = string.Empty;
+ this.RelationTypeId = -1;
+ this.ReverseIndexing = false;
+ this.HideDataEditor = false;
+ }
+ }
+}
diff --git a/components/editorControls/PickerRelations/PickerRelationsPreValueEditor.cs b/components/editorControls/PickerRelations/PickerRelationsPreValueEditor.cs
new file mode 100644
index 0000000000..93b95b68de
--- /dev/null
+++ b/components/editorControls/PickerRelations/PickerRelationsPreValueEditor.cs
@@ -0,0 +1,235 @@
+using System;
+using System.Linq;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using umbraco.cms.businesslogic.datatype;
+using umbraco.cms.businesslogic.relation;
+using umbraco.macroRenderings;
+
+namespace umbraco.editorControls.PickerRelations
+{
+ ///
+ /// 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
+ ///
+ public class PickerRelationsPreValueEditor : AbstractJsonPrevalueEditor
+ {
+ ///
+ /// Prepopulated Umbraco Propery Picker, lists all aliases (could refine this by asking for the context in which this relation wire-up will
+ /// be used, and then only listing the aliases for that context)
+ ///
+ private propertyTypePicker pickerPropertyAliasPicker = new propertyTypePicker();
+
+ ///
+ /// RequiredFieldValidator for the ProperyAliasPicker
+ ///
+ private RequiredFieldValidator pickerPropertyAliasRequiredFieldValidator = new RequiredFieldValidator();
+
+ ///
+ /// drop down list of all relation types
+ ///
+ private DropDownList relationTypeDropDownList = new DropDownList();
+
+ ///
+ /// RequiredFieldValidator for the RelationType DropDownList
+ ///
+ private RequiredFieldValidator relationTypeRequiredFieldValidator = new RequiredFieldValidator();
+
+ ///
+ /// If a parent to child relation type is selected, then this checkbox will indicate the direction to use,
+ /// with reverse indexing the parents are the nodes selected via the picker, and the nodeID on which the
+ /// this datatype is used, become the child nodes
+ ///
+ private CheckBox reverseIndexingCheckBox = new CheckBox();
+
+ ///
+ /// if selected, then the property on the data editor is hidden (it's only used as a label)
+ ///
+ private CheckBox hideDataEditorCheckBox = new CheckBox();
+
+ ///
+ /// Data object used to define the configuration status of this PreValueEditor
+ ///
+ private PickerRelationsOptions options = null;
+
+ ///
+ /// Currently selected RelationType
+ ///
+ private RelationType relationType = null;
+
+ ///
+ /// Lazy load the options data object that represents the current state of this datatypes configuration
+ ///
+ internal PickerRelationsOptions 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 PickerRelationsOptions();
+ }
+ }
+ return this.options;
+ }
+ }
+
+ ///
+ /// Lazy load currently selected RelationType
+ ///
+ private RelationType RelationType
+ {
+ get
+ {
+ if (this.relationType == null)
+ {
+ // Attempt to get RelationType from the selected DropDownList item
+ int relationTypeId;
+ if(int.TryParse(this.relationTypeDropDownList.SelectedValue, out relationTypeId))
+ {
+ if (relationTypeId != -1)
+ {
+ this.relationType = new RelationType(relationTypeId);
+ }
+ }
+ }
+
+ return this.relationType;
+ }
+ }
+
+ ///
+ /// Initialize a new instance of PickerRelationsPreValueEditor
+ ///
+ /// PickerRelationsDataType
+ public PickerRelationsPreValueEditor(umbraco.cms.businesslogic.datatype.BaseDataType dataType)
+ : base(dataType, umbraco.cms.businesslogic.datatype.DBTypes.Nvarchar)
+ {
+ }
+
+ ///
+ /// Creates all of the controls and assigns all of their properties
+ ///
+ protected override void CreateChildControls()
+ {
+ this.pickerPropertyAliasPicker.ID = "pickerPropertyAliasPicker";
+
+ this.pickerPropertyAliasRequiredFieldValidator.Text = " Required";
+ this.pickerPropertyAliasRequiredFieldValidator.InitialValue = string.Empty;
+ this.pickerPropertyAliasRequiredFieldValidator.ControlToValidate = this.pickerPropertyAliasPicker.ID;
+
+ this.relationTypeDropDownList.ID = "relationTypeDropDownList";
+ this.relationTypeDropDownList.AutoPostBack = true;
+ this.relationTypeDropDownList.DataSource = RelationType.GetAll().OrderBy(x => x.Name);
+ this.relationTypeDropDownList.DataTextField = "Name";
+ this.relationTypeDropDownList.DataValueField = "Id";
+ this.relationTypeDropDownList.DataBind();
+ this.relationTypeDropDownList.Items.Insert(0, new ListItem(string.Empty, "-1"));
+
+ this.relationTypeRequiredFieldValidator.Text = " Required";
+ this.relationTypeRequiredFieldValidator.InitialValue = "-1";
+ this.relationTypeRequiredFieldValidator.ControlToValidate = this.relationTypeDropDownList.ID;
+
+ this.Controls.Add(this.pickerPropertyAliasPicker);
+ this.Controls.Add(this.pickerPropertyAliasRequiredFieldValidator);
+ this.Controls.Add(this.relationTypeDropDownList);
+ this.Controls.Add(this.relationTypeRequiredFieldValidator);
+ this.Controls.Add(this.reverseIndexingCheckBox);
+ this.Controls.Add(this.hideDataEditorCheckBox);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ protected override void OnLoad(EventArgs e)
+ {
+ base.OnLoad(e);
+
+ if (!this.Page.IsPostBack)
+ {
+ // Read in stored configuration values
+ if (this.pickerPropertyAliasPicker.Items.Contains(new ListItem(this.Options.PropertyAlias)))
+ {
+ this.pickerPropertyAliasPicker.SelectedValue = this.Options.PropertyAlias;
+ }
+
+ if (this.relationTypeDropDownList.Items.FindByValue(this.Options.RelationTypeId.ToString()) != null)
+ {
+ this.relationTypeDropDownList.SelectedValue = this.Options.RelationTypeId.ToString();
+ }
+
+ this.reverseIndexingCheckBox.Checked = this.Options.ReverseIndexing;
+
+ this.hideDataEditorCheckBox.Checked = this.Options.HideDataEditor;
+ }
+ }
+
+ ///
+ /// Saves the pre value data to Umbraco
+ ///
+ public override void Save()
+ {
+ if (this.Page.IsValid)
+ {
+ this.Options.PropertyAlias = this.pickerPropertyAliasPicker.SelectedValue;
+ if (this.RelationType != null)
+ {
+ this.Options.RelationTypeId = this.RelationType.Id;
+ }
+
+ this.Options.ReverseIndexing = this.reverseIndexingCheckBox.Checked;
+
+ this.Options.HideDataEditor = this.hideDataEditorCheckBox.Checked;
+
+ // Serialize to Umbraco database field
+ this.SaveAsJson(this.Options);
+ }
+ }
+
+ ///
+ /// Used to remove styling from the built in pickerProperty alias picker DropDownList
+ ///
+ ///
+ protected override void OnPreRender(EventArgs e)
+ {
+ base.OnPreRender(e);
+
+ this.pickerPropertyAliasPicker.CssClass = string.Empty; // Remove guiInputTextStandard
+
+ // Sort properties in the built in property picker control
+ ListItem[] propertyAliasListItems = this.pickerPropertyAliasPicker.Items.Cast().OrderBy(x => x.Text).ToArray();
+
+ this.pickerPropertyAliasPicker.Items.Clear();
+ this.pickerPropertyAliasPicker.Items.AddRange(propertyAliasListItems);
+ }
+
+ ///
+ /// 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("Picker Alias", this.pickerPropertyAliasPicker, this.pickerPropertyAliasRequiredFieldValidator);
+ writer.AddPrevalueRow("Relation Type", this.relationTypeDropDownList, this.relationTypeRequiredFieldValidator);
+
+ // Only show this field if selected RelationType is of Parent to Child
+ if (this.RelationType != null)
+ {
+ if (!this.RelationType.Dual)
+ {
+ writer.AddPrevalueRow("Reverse Indexing", this.reverseIndexingCheckBox);
+ }
+ }
+
+ writer.AddPrevalueRow("Hide Data Editor", this.hideDataEditorCheckBox);
+ }
+ }
+}
diff --git a/components/editorControls/umbraco.editorControls.csproj b/components/editorControls/umbraco.editorControls.csproj
index 94d6856f71..02515eaeaa 100644
--- a/components/editorControls/umbraco.editorControls.csproj
+++ b/components/editorControls/umbraco.editorControls.csproj
@@ -156,6 +156,10 @@
{651E1350-91B6-44B7-BD60-7207006D7003}
umbraco.presentation
+
+ {52AB8F1F-FB76-4E8C-885F-0747B6CE71EC}
+ umbraco.macroRenderings
+
{6EDD2061-82F2-461B-BB6E-879245A832DE}
umbraco.controls
@@ -314,6 +318,11 @@
Code
+
+
+
+
+
Code