From c2d45adcb966b3f7701e3c38bef7c2bbe21d6581 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Sat, 28 Apr 2012 13:54:03 -0100 Subject: [PATCH] uComponents: Added Slider to the core --- .../editorControls/Slider/SliderControl.cs | 181 +++++++++++ .../editorControls/Slider/SliderDataType.cs | 157 +++++++++ .../editorControls/Slider/SliderOptions.cs | 99 ++++++ .../Slider/SliderPrevalueEditor.cs | 303 ++++++++++++++++++ 4 files changed, 740 insertions(+) create mode 100644 components/editorControls/Slider/SliderControl.cs create mode 100644 components/editorControls/Slider/SliderDataType.cs create mode 100644 components/editorControls/Slider/SliderOptions.cs create mode 100644 components/editorControls/Slider/SliderPrevalueEditor.cs diff --git a/components/editorControls/Slider/SliderControl.cs b/components/editorControls/Slider/SliderControl.cs new file mode 100644 index 0000000000..6f3aca6fce --- /dev/null +++ b/components/editorControls/Slider/SliderControl.cs @@ -0,0 +1,181 @@ +using System; +using System.Text; +using System.Web.UI; +using System.Web.UI.HtmlControls; +using System.Web.UI.WebControls; +using umbraco.cms.businesslogic.datatype; + +namespace umbraco.editorControls.Slider +{ + /// + /// The jQuery UI Slider control. + /// + [ClientDependency.Core.ClientDependency(ClientDependency.Core.ClientDependencyType.Javascript, "ui/jqueryui.js", "UmbracoClient")] + [ClientDependency.Core.ClientDependency(ClientDependency.Core.ClientDependencyType.Css, "DateTimePicker/datetimepicker.css", "UmbracoClient")] + [ValidationProperty("Text")] + public class SliderControl : PlaceHolder + { + /// + /// Gets or sets the slider options. + /// + /// The slider options. + public SliderOptions Options { get; set; } + + /// + /// Gets or sets the text. + /// + /// The text value. + public string Text + { + get + { + return this.TextBoxControl.Text; + } + + set + { + if (this.TextBoxControl == null) + { + this.TextBoxControl = new TextBox(); + } + + this.TextBoxControl.Text = value; + } + } + + /// + /// Gets or sets the TextBox control that contains the value(s) of the slider. + /// + /// The text box control. + protected TextBox TextBoxControl { get; set; } + + /// + /// Gets or sets the HtmlGenericControl control for the slider <div> tag. + /// + /// The div slider control. + protected HtmlGenericControl DivSliderControl { get; set; } + + /// + /// Initialize the control, make sure children are created + /// + /// An object that contains the event data. + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + + this.EnsureChildControls(); + } + + /// + /// Add the resources (sytles/scripts) + /// + /// The object that contains the event data. + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + // TODO: [LK] Move 'jquery.alphanumeric.js' into Shared/Resources + this.AddResourceToClientDependency("uComponents.Core.DataTypes.IncrementalTextBox.Scripts.jquery.alphanumeric.js", ClientDependency.Core.ClientDependencyType.Javascript); + } + + /// + /// 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() + { + base.CreateChildControls(); + + this.EnsureChildControls(); + + var divStyle = this.Options.Orientation.Equals("vertical") ? "float:left;margin:0 10px 0 0;height:150px;" : "float:left;margin:7px 10px 0 0;width:342px;"; + + this.DivSliderControl = new HtmlGenericControl("div"); + this.DivSliderControl.ID = this.DivSliderControl.ClientID; + this.DivSliderControl.Attributes.Add("style", divStyle); + this.Controls.Add(this.DivSliderControl); + + this.TextBoxControl = new TextBox(); + this.TextBoxControl.ID = this.TextBoxControl.ClientID; + this.TextBoxControl.CssClass = "guiInputTextTiny"; + this.TextBoxControl.Attributes.Add("style", "float:left;width:40px;"); + this.TextBoxControl.MaxLength = this.Options.EnableRange ? (this.Options.MaxValue.ToString().Length * 2) + 1 : this.Options.MaxValue.ToString().Length; + this.Controls.Add(this.TextBoxControl); + } + + /// + /// Sends server control content to a provided object, which writes the content to be rendered on the client. + /// + /// The object that receives the server control content. + protected override void Render(HtmlTextWriter writer) + { + writer.AddAttribute("id", this.ClientID); + writer.AddAttribute("class", "jqueryui-slider"); + writer.AddAttribute("style", "float:left;width:400px;"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + + this.DivSliderControl.RenderControl(writer); + + this.TextBoxControl.RenderControl(writer); + + writer.RenderEndTag(); + + // construct slider options + bool hasMultipleValues = false; + var options = new StringBuilder(); + + // add range + if (this.Options.EnableRange) + { + if (!string.IsNullOrEmpty(this.Options.RangeValue)) + { + options.Append("range: '").Append(this.Options.RangeValue).Append("', "); + } + else + { + // the options can only have multiple values if the range is set to 'true'. + if (this.Options.Value2 >= this.Options.Value) + { + options.Append("range: true,values: [").Append(this.Options.Value).Append(',').Append(this.Options.Value2).Append("],"); + hasMultipleValues = true; + } + } + } + + // add value - if multiple values have not been already set. + if (!hasMultipleValues) + { + options.Append("value: ").Append(this.Options.Value).Append(','); + } + + // add min.max values + if (this.Options.MaxValue > this.Options.MinValue) + { + options.Append("min: ").Append(this.Options.MinValue).Append(','); + options.Append("max: ").Append(this.Options.MaxValue).Append(','); + } + + // add step increments + if (this.Options.EnableStep) + { + options.Append("step: ").Append(this.Options.StepValue).Append(','); + } + + // add orientation + if (!string.IsNullOrEmpty(this.Options.Orientation)) + { + options.Append("orientation: '").Append(this.Options.Orientation).Append("'").Append(','); + } + + // add jquery window load event to create the js slider + var javascriptMethod = string.Format( + "jQuery('#{0}').slider({{ {2} slide: function(e, ui) {{ $('#{1}').val(ui.value{3}); }} }}); $('#{1}').val($('#{0}').slider('value{3}')); jQuery('#{1}').numeric({4});", + this.DivSliderControl.ClientID, + this.TextBoxControl.ClientID, + options, + (hasMultipleValues ? "s" : string.Empty), + (hasMultipleValues ? "{ allow: ',' }" : string.Empty)); + var javascript = string.Concat(""); + writer.WriteLine(javascript); + } + } +} \ No newline at end of file diff --git a/components/editorControls/Slider/SliderDataType.cs b/components/editorControls/Slider/SliderDataType.cs new file mode 100644 index 0000000000..460befb8d6 --- /dev/null +++ b/components/editorControls/Slider/SliderDataType.cs @@ -0,0 +1,157 @@ +using System; +// using uComponents.Core; +using umbraco.cms.businesslogic.datatype; +using umbraco.interfaces; + +namespace umbraco.editorControls.Slider +{ + /// + /// A jQuery UI Slider data-type for Umbraco. + /// + public class SliderDataType : AbstractDataEditor + { + /// + /// The SliderControl. + /// + private SliderControl m_Control = new SliderControl(); + + /// + /// The PreValue Editor for the data-type. + /// + private SliderPrevalueEditor m_PreValueEditor; + + /// + /// Initializes a new instance of the class. + /// + public SliderDataType() + : base() + { + // set the render control as the placeholder + this.RenderControl = this.m_Control; + + // assign the initialise event for the placeholder + this.m_Control.Init += new EventHandler(this.m_Control_Init); + + // assign the save event for the data-type/editor + this.DataEditorControl.OnSave += new AbstractDataEditorControl.SaveEventHandler(this.DataEditorControl_OnSave); + } + + /// + /// Gets the id of the data-type. + /// + /// The id of the data-type. + public override Guid Id + { + get + { + return new Guid(DataTypeGuids.SliderId); + } + } + + /// + /// Gets the name of the data type. + /// + /// The name of the data type. + public override string DataTypeName + { + get + { + return "Slider"; + } + } + + /// + /// Gets the prevalue editor. + /// + /// The prevalue editor. + public override IDataPrevalue PrevalueEditor + { + get + { + if (this.m_PreValueEditor == null) + { + this.m_PreValueEditor = new SliderPrevalueEditor(this); + } + + return this.m_PreValueEditor; + } + } + + /// + /// Handles the Init event of the m_Placeholder control. + /// + /// The source of the event. + /// The instance containing the event data. + private void m_Control_Init(object sender, EventArgs e) + { + // get the slider options from the Prevalue Editor. + var options = ((SliderPrevalueEditor)this.PrevalueEditor).GetPreValueOptions(); + + // set the value of the control (not on PostBack) + if (!this.m_Control.Page.IsPostBack && this.Data.Value != null) + { + var data = this.Data.Value.ToString(); + if (data.Length > 0) + { + double value1, value2; + var values = data.Split(','); + + if (double.TryParse(values[0], out value1)) + { + options.Value = value1; + + if (values.Length > 1 && double.TryParse(values[1], out value2)) + { + options.Value2 = value2; + } + } + } + } + + // set the slider options + this.m_Control.Options = options; + } + + /// + /// Saves the editor control value. + /// + /// The instance containing the event data. + private void DataEditorControl_OnSave(EventArgs e) + { + // set the values (on PostBack) + var value1 = this.m_Control.Options.MinValue; + var value2 = this.m_Control.Options.MaxValue; + var values = this.m_Control.Text.Split(','); + + if (double.TryParse(values[0], out value1)) + { + this.m_Control.Options.Value = value1; + + if (values.Length > 1 && double.TryParse(values[1], out value2)) + { + this.m_Control.Options.Value2 = value2; + } + } + + // save the value of the control + if (values.Length > 1 && value2 >= this.m_Control.Options.MinValue && value2 <= this.m_Control.Options.MaxValue) + { + this.Data.Value = string.Concat(value1, ',', value2); + } + else if (value1 >= this.m_Control.Options.MinValue && value1 <= this.m_Control.Options.MaxValue) + { + int value1int; + + // return an integer instead of double if applicable + if (this.m_Control.Options.DBType == DBTypes.Integer && int.TryParse(value1.ToString(), out value1int)) + { + this.Data.Value = value1int; + } + else + { + this.Data.Value = value1; + } + } + } + } +} \ No newline at end of file diff --git a/components/editorControls/Slider/SliderOptions.cs b/components/editorControls/Slider/SliderOptions.cs new file mode 100644 index 0000000000..8551d5d518 --- /dev/null +++ b/components/editorControls/Slider/SliderOptions.cs @@ -0,0 +1,99 @@ +using System.ComponentModel; +// using uComponents.DataTypes.Shared.PrevalueEditors; +using umbraco.cms.businesslogic.datatype; + +namespace umbraco.editorControls.Slider +{ + /// + /// The options for the Slider data-type. + /// + public class SliderOptions : AbstractOptions + { + /// + /// Initializes a new instance of the class. + /// + public SliderOptions() + : base() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// if set to true [loads defaults]. + public SliderOptions(bool loadDefaults) + : base(loadDefaults) + { + } + + /// + /// Gets or sets a value indicating whether [enable range]. + /// + /// true if [enable range]; otherwise, false. + [DefaultValue(false)] + public bool EnableRange { get; set; } + + /// + /// Gets or sets a value indicating whether [enable step]. + /// + /// true if [enable step]; otherwise, false. + [DefaultValue(true)] + public bool EnableStep { get; set; } + + /// + /// Gets or sets the max value. + /// + /// The max value. + [DefaultValue(100)] + public double MaxValue { get; set; } + + /// + /// Gets or sets the min value. + /// + /// The min value. + [DefaultValue(0)] + public double MinValue { get; set; } + + /// + /// Gets or sets the orientation. + /// + /// The orientation. + [DefaultValue("hortizontal")] + public string Orientation { get; set; } + + /// + /// Gets or sets the range value. + /// + /// The range value. + [DefaultValue("")] + public string RangeValue { get; set; } + + /// + /// Gets or sets the step. + /// + /// The step. + [DefaultValue(5)] + public double StepValue { get; set; } + //public int StepValue { get; set; } + + /// + /// Gets or sets the value. + /// + /// The value. + [DefaultValue(50)] + public double Value { get; set; } + + /// + /// Gets or sets the second value. + /// + /// The second value. + [DefaultValue(0)] + public double Value2 { get; set; } + + /// + /// Gets or sets the Database Storage Type + /// + [DefaultValue(DBTypes.Integer)] + public DBTypes DBType { get; set; } + } +} diff --git a/components/editorControls/Slider/SliderPrevalueEditor.cs b/components/editorControls/Slider/SliderPrevalueEditor.cs new file mode 100644 index 0000000000..26964b0e26 --- /dev/null +++ b/components/editorControls/Slider/SliderPrevalueEditor.cs @@ -0,0 +1,303 @@ +using System; +using System.Web.UI; +using System.Web.UI.WebControls; +// using uComponents.DataTypes.Shared.Extensions; +// using uComponents.DataTypes.Shared.PrevalueEditors; +using umbraco.cms.businesslogic.datatype; + +namespace umbraco.editorControls.Slider +{ + /// + /// The PreValue Editor for the Slider data-type. + /// + [ClientDependency.Core.ClientDependency(ClientDependency.Core.ClientDependencyType.Javascript, "ui/jqueryui.js", "UmbracoClient")] + [ClientDependency.Core.ClientDependency(ClientDependency.Core.ClientDependencyType.Css, "DateTimePicker/datetimepicker.css", "UmbracoClient")] + public class SliderPrevalueEditor : AbstractJsonPrevalueEditor + { + /// + /// The DropDownList for the database data-type. + /// + private DropDownList DatabaseDataType; + + /// + /// The CheckBox control to enable the range for the slider. + /// + private CheckBox EnableRange; + + /// + /// The CheckBox control to enable incremental steps for the slider. + /// + private CheckBox EnableStep; + + /// + /// The TextBox control for the minimum value of the slider. + /// + private TextBox MinValue; + + /// + /// The TextBox control for the maximum value of the slider. + /// + private TextBox MaxValue; + + /// + /// The DropDownList control for the orientation of the slider. + /// + private DropDownList Orientation; + + /// + /// The DropDownList control for the range value. + /// + private DropDownList RangeValue; + + /// + /// The TextBox control for the incremental step value. + /// + private TextBox StepValue; + + /// + /// The TextBox control for the first value input. + /// + private TextBox Value; + + /// + /// The TextBox control for the second value input. + /// + private TextBox Value2; + + ////private SliderControl PreviewSlider; + + /// + /// Initializes a new instance of the class. + /// + /// Type of the data. + public SliderPrevalueEditor(umbraco.cms.businesslogic.datatype.BaseDataType dataType) + : base(dataType) + { + } + + /// + /// Saves the data-type PreValue options. + /// + public override void Save() + { + // set the database data-type + this.m_DataType.DBType = (umbraco.cms.businesslogic.datatype.DBTypes)Enum.Parse(typeof(umbraco.cms.businesslogic.datatype.DBTypes), this.DatabaseDataType.SelectedValue); + + // parse the integers & doubles + double maxValue, minValue, value, value2, stepValue; + double.TryParse(this.MaxValue.Text, out maxValue); + double.TryParse(this.MinValue.Text, out minValue); + double.TryParse(this.Value.Text, out value); + double.TryParse(this.Value2.Text, out value2); + double.TryParse(this.StepValue.Text, out stepValue); + + // set the options + var options = new SliderOptions() + { + DBType = (DBTypes)Enum.Parse(typeof(DBTypes), this.DatabaseDataType.SelectedValue), + EnableRange = this.EnableRange.Checked, + EnableStep = this.EnableStep.Checked, + MaxValue = maxValue, + MinValue = minValue, + Orientation = this.Orientation.SelectedValue, + RangeValue = this.RangeValue.SelectedValue, + StepValue = stepValue, + Value = value, + Value2 = value2 + }; + + // save the options as JSON + this.SaveAsJson(options); + + // toggle the non-default fields + this.ToggleFields(); + } + + /// + /// Raises the event. + /// + /// An object that contains the event data. + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + this.EnsureChildControls(); + } + + /// + /// Creates child controls for this control + /// + protected override void CreateChildControls() + { + base.CreateChildControls(); + + // set-up child controls + this.DatabaseDataType = new DropDownList() { ID = "DatabaseDataType" }; + this.EnableRange = new CheckBox() { ID = "EnableRange" }; + this.EnableStep = new CheckBox() { ID = "EnableStep" }; + this.MinValue = new TextBox() { ID = "MinValue", CssClass = "guiInputText slider-numeric slider-decimal" }; + this.MaxValue = new TextBox() { ID = "MaxValue", CssClass = "guiInputText slider-numeric slider-decimal" }; + this.Orientation = new DropDownList() { ID = "Orientation" }; + this.RangeValue = new DropDownList() { ID = "RangeValue" }; + this.StepValue = new TextBox() { ID = "StepValue", CssClass = "guiInputText slider-numeric slider-decimal" }; + this.Value = new TextBox() { ID = "Value", CssClass = "guiInputText slider-numeric slider-decimal" }; + this.Value2 = new TextBox() { ID = "Value2", CssClass = "guiInputText slider-numeric slider-decimal" }; + ////this.PreviewSlider = new SliderControl() { ID = "PreviewSlider", Options = new SliderOptions(true) }; + + // add the database data-type options + this.DatabaseDataType.Items.Clear(); + this.DatabaseDataType.Items.Add(DBTypes.Integer.ToString()); + //this.DatabaseDataType.Items.Add(DBTypes.Ntext.ToString()); + this.DatabaseDataType.Items.Add(DBTypes.Nvarchar.ToString()); + + // add range options + this.RangeValue.Items.Clear(); + this.RangeValue.Items.Add(string.Empty); + this.RangeValue.Items.Add(new ListItem("Minimum Value", "min")); + this.RangeValue.Items.Add(new ListItem("Maximum Value", "max")); + + // add orientation options + this.Orientation.Items.Clear(); + this.Orientation.Items.Add(new ListItem("Horizontal (default)", "horizontal")); + this.Orientation.Items.Add(new ListItem("Vertical", "vertical")); + + // add the child controls + this.Controls.AddPrevalueControls(this.DatabaseDataType, this.EnableRange, this.EnableStep, this.MaxValue, this.MinValue, this.Orientation, this.RangeValue, this.StepValue, this.Value, this.Value2); + ////this.Controls.Add(this.PreviewSlider); + } + + /// + /// Raises the event. + /// + /// The object that contains the event data. + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + // get PreValues, load them into the controls. + var options = this.GetPreValueOptions(); + + // if the options are null, then load the defaults + if (options == null) + { + options = new SliderOptions(true); + } + + // set the values + this.DatabaseDataType.SelectedValue = this.m_DataType.DBType.ToString(); + this.EnableRange.Checked = options.EnableRange; + this.EnableStep.Checked = options.EnableStep; + this.MinValue.Text = options.MinValue.ToString(); + this.MaxValue.Text = options.MaxValue.ToString(); + this.Orientation.SelectedValue = options.Orientation; + this.RangeValue.SelectedValue = options.RangeValue; + this.StepValue.Text = options.StepValue.ToString(); + this.Value.Text = options.Value.ToString(); + this.Value2.Text = options.Value2.ToString(); + + // toggle the non-default fields + this.ToggleFields(); + } + + /// + /// Renders the contents of the control to the specified writer. This method is used primarily by control developers. + /// + /// A that represents the output stream to render HTML content on the client. + protected override void RenderContents(HtmlTextWriter writer) + { + // add property fields + writer.AddPrevalueRow("Database Type:", this.DatabaseDataType); + writer.AddPrevalueRow("Enable Range:", this.EnableRange); + writer.AddPrevalueRow("Range:", this.RangeValue); + writer.AddPrevalueRow("Initial Value:", this.Value); + writer.AddPrevalueRow("Initial Value 2:", this.Value2); + writer.AddPrevalueRow("Minimum Value:", this.MinValue); + writer.AddPrevalueRow("Maximum Value:", this.MaxValue); + writer.AddPrevalueRow("Enable Step Increments:", this.EnableStep); + writer.AddPrevalueRow("Step Increments:", this.StepValue); + writer.AddPrevalueRow("Orientation:", this.Orientation); + + ////writer.AddPrevalueRow(" ", new LiteralControl("

Preview:


"), this.PreviewSlider); + + // add jquery window load event for toggling fields. + var javascriptMethod = string.Format( + @" +$('#{0}').click(function(){{ + var disable = !$(this).attr('checked'); + $('#{1},#{3}').attr('disabled', disable); + $('#{6}').val(disable && !checkDecimals() ? 'Integer' : 'Nvarchar'); + if(!disable) disable = $('#{1}').val() != ''; + +}}); +$('#{1}').change(function(){{ + var disable = $(this).val() != ''; + $('#{3}').attr('disabled', disable); +}}); +$('#{4}').click(function(){{ + var disable = !$(this).attr('checked'); + $('#{5}').attr('disabled', disable); +}}); +$('#{6}').change(function(){{ + var disable = $(this).val() == 'Integer'; + if (checkDecimals() && disable) {{ + $('#{6}').val('Nvarchar'); + alert('Please remove decimal points below if you wish to use the Integer datatype'); + }} + else {{ + $('#{0}').removeAttr('checked'); + $('#{1},#{3}').attr('disabled', disable); + }} +}}); +$('.slider-numeric').keydown(function(event) {{ + // Allow only backspace and delete + if ( event.keyCode == 46 || event.keyCode == 8 || ($(this).hasClass('slider-decimal') && (event.keyCode == 110 || event.keyCode == 190))) {{ + // let it happen, don't do anything + }} else {{ + // Ensure that it is a number and stop the keypress + if ( (event.keyCode < 48 || event.keyCode > 57 ) && (event.keyCode < 96 || event.keyCode > 105 ) ) {{ + event.preventDefault(); + }} + }} +}}); +$('.slider-numeric').keyup(function(event) {{ + if ($('#{6}').val() != 'Nvarchar' && checkDecimals()) {{ + $('#{6}').val('Nvarchar'); + }} +}}); +function checkDecimals() {{ + foundDecimals = false; + $('.slider-numeric').each(function() {{ + if ($(this).val().indexOf('.') >= 0) {{ + foundDecimals = true; + return false; + }} + }}); + return foundDecimals; +}} +", + this.EnableRange.ClientID, + this.RangeValue.ClientID, + this.Value.ClientID, + this.Value2.ClientID, + this.EnableStep.ClientID, + this.StepValue.ClientID, + this.DatabaseDataType.ClientID); + var javascript = string.Concat(""); + writer.WriteLine(javascript); + } + + /// + /// Toggles the fields. + /// + private void ToggleFields() + { + if (this.DatabaseDataType.SelectedIndex == 0) + { + this.EnableRange.Checked = false; + } + + this.RangeValue.Enabled = this.EnableRange.Checked; + this.Value2.Enabled = this.EnableRange.Checked && this.RangeValue.SelectedValue == string.Empty; + this.StepValue.Enabled = this.EnableStep.Checked; + } + } +}