diff --git a/src/Umbraco.Core/Models/PreValueCollection.cs b/src/Umbraco.Core/Models/PreValueCollection.cs index 154e4a58ad..995f6422c2 100644 --- a/src/Umbraco.Core/Models/PreValueCollection.cs +++ b/src/Umbraco.Core/Models/PreValueCollection.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Models /// public class PreValueCollection { - private IDictionary _preValuesAsDictionary; + private IDictionary _preValuesAsDictionary; private IEnumerable _preValuesAsArray; public IEnumerable PreValuesAsArray { @@ -30,7 +30,7 @@ namespace Umbraco.Core.Models set { _preValuesAsArray = value; } } - public IDictionary PreValuesAsDictionary + public IDictionary PreValuesAsDictionary { get { @@ -56,7 +56,7 @@ namespace Umbraco.Core.Models _preValuesAsArray = preVals; } - public PreValueCollection(IDictionary preVals) + public PreValueCollection(IDictionary preVals) { _preValuesAsDictionary = preVals; } diff --git a/src/Umbraco.Core/Models/PropertyExtensions.cs b/src/Umbraco.Core/Models/PropertyExtensions.cs index 53ed83baca..5e3328de56 100644 --- a/src/Umbraco.Core/Models/PropertyExtensions.cs +++ b/src/Umbraco.Core/Models/PropertyExtensions.cs @@ -64,8 +64,15 @@ namespace Umbraco.Core.Models } else { - var dt = (DateTime)property.Value; - xmlNode.AppendChild(xd.CreateTextNode(dt.ToXmlString())); + var date = property.Value.TryConvertTo(); + if (date.Success == false || date.Result == null) + { + xmlNode.AppendChild(xd.CreateTextNode(string.Empty)); + } + else + { + xmlNode.AppendChild(xd.CreateTextNode(date.Result.ToXmlString())); + } } break; default: diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 5f5e41b1ef..6a4ba31f05 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -77,7 +77,14 @@ namespace Umbraco.Core /// public static Attempt TryConvertTo(this object input, Type destinationType) { - if (input == null) return Attempt.False; + //if it is null and it is nullable, then return success with null + if (input == null && destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof (Nullable<>)) + { + return new Attempt(true, null); + } + + //if its not nullable then return false + if (input == null) return Attempt.False; if (destinationType == typeof(object)) return new Attempt(true, input); diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs index 3c23bc9991..bb69b0a445 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs @@ -73,7 +73,7 @@ namespace Umbraco.Core.PropertyEditors } [JsonProperty("defaultConfig")] - public virtual IDictionary DefaultPreValues { get; set; } + public virtual IDictionary DefaultPreValues { get; set; } //TODO: Now we need to implement a couple of methods for saving the data for editors and pre-value editors // generally we can handle that automatically in this base class but people should be allowed to override @@ -122,13 +122,13 @@ namespace Umbraco.Core.PropertyEditors /// /// /// This is generally not going to be used by anything unless a property editor wants to change the merging - /// functionality or needs to convert some legacy persisted data, or something else ? + /// functionality or needs to convert some legacy persisted data, or convert the string values to strongly typed values in json (i.e. booleans) /// - public virtual IDictionary FormatPreValues(IDictionary defaultPreVals, PreValueCollection persistedPreVals) + public virtual IDictionary FormatPreValues(IDictionary defaultPreVals, PreValueCollection persistedPreVals) { if (defaultPreVals == null) { - defaultPreVals = new Dictionary(); + defaultPreVals = new Dictionary(); } if (persistedPreVals.IsDictionaryBased) @@ -142,7 +142,7 @@ namespace Umbraco.Core.PropertyEditors } //it's an array so need to format it - var result = new Dictionary(); + var result = new Dictionary(); var asArray = persistedPreVals.PreValuesAsArray.ToArray(); for (var i = 0; i < asArray.Length; i++) { diff --git a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs index 8f8f23a056..5929b96512 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs @@ -185,17 +185,14 @@ namespace Umbraco.Core.PropertyEditors case DataTypeDatabaseType.Integer: //we can just ToString() any of these types return dbValue.ToString(); - case DataTypeDatabaseType.Date: - var s = dbValue as string; - if (s != null) + case DataTypeDatabaseType.Date: + var date = dbValue.TryConvertTo(); + if (date.Success == false || date.Result == null) { - if (s.IsNullOrWhiteSpace()) - { - return string.Empty; - } + return string.Empty; } - //Dates will be formatted in 'o' format (otherwise known as xml format) - return dbValue.ToXmlString(); + //Dates will be formatted as yyyy-MM-dd HH:mm:ss + return date.Result.Value.ToIsoString(); default: throw new ArgumentOutOfRangeException(); } diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 3a2bc3a4f2..3a1e2e8f46 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -354,7 +354,7 @@ namespace Umbraco.Core.Services internal static PreValueCollection ConvertToPreValuesCollection(IEnumerable> list) { //now we need to determine if they are dictionary based, otherwise they have to be array based - var dictionary = new Dictionary(); + var dictionary = new Dictionary(); //need to check all of the keys, if there's only one and it is empty then it's an array var keys = list.Select(x => x.Item2).Distinct().ToArray(); diff --git a/src/Umbraco.Web.UI.Client/lib/umbraco/Extensions.js b/src/Umbraco.Web.UI.Client/lib/umbraco/Extensions.js index 43e957d6ed..306b9d01c6 100644 --- a/src/Umbraco.Web.UI.Client/lib/umbraco/Extensions.js +++ b/src/Umbraco.Web.UI.Client/lib/umbraco/Extensions.js @@ -28,6 +28,23 @@ return this.getFullYear() + "-" + month + "-" + day + " " + hour + ":" + mins + ":" + secs; }; } + + if (!Date.prototype.toIsoDateString) { + /** Converts a Date object to a globally acceptable ISO string, NOTE: This is different from the built in + JavaScript toISOString method which returns date/time like "2013-08-07T02:04:11.487Z" but we want "yyyy-MM-dd" */ + Date.prototype.toIsoDateString = function (str) { + var month = (this.getMonth() + 1).toString(); + if (month.length === 1) { + month = "0" + month; + } + var day = this.getDate().toString(); + if (day.length === 1) { + day = "0" + day; + } + + return this.getFullYear() + "-" + month + "-" + day; + }; + } //create guid method on the String if (String.CreateGuid == null) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index da111b9d5b..5eca3e1323 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -25,7 +25,12 @@ angular.module("umbraco").controller("Umbraco.Editors.DatepickerController", $("#" + pickerId).datetimepicker($scope.model.config).on("changeDate", function (e) { // when a date is changed, update the model if (e.localDate) { - $scope.model.value = e.localDate.toIsoDateTimeString(); + if ($scope.model.config.format == "yyyy-MM-dd HH:mm:ss") { + $scope.model.value = e.localDate.toIsoDateTimeString(); + } + else { + $scope.model.value = e.localDate.toIsoDateString(); + } } else { $scope.model.value = null; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html index 10f1a715ee..25921f3c0e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html @@ -1,6 +1,6 @@
- diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs index a087840f34..0e78f125c1 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Models.ContentEditing public string View { get; set; } [DataMember(Name = "config")] - public IDictionary Config { get; set; } + public IDictionary Config { get; set; } [DataMember(Name = "hideLabel")] public bool HideLabel { get; set; } diff --git a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs index 06458928f0..135a76ee3a 100644 --- a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Newtonsoft.Json.Linq; @@ -10,13 +11,58 @@ namespace Umbraco.Web.PropertyEditors [PropertyEditor(Constants.PropertyEditors.Date, "Date", "datepicker", ValueType = "DATE")] public class DatePropertyEditor : PropertyEditor { + public DatePropertyEditor() + { + _defaultPreVals = new Dictionary + { + {"format", "yyyy-MM-dd"}, + {"pickTime", false} + }; + } + + private IDictionary _defaultPreVals; + + /// + /// Overridden because we ONLY support Date (no time) format and we don't have pre-values in the db. + /// + public override IDictionary DefaultPreValues + { + get { return _defaultPreVals; } + set { _defaultPreVals = value; } + } + protected override ValueEditor CreateValueEditor() { - var editor = base.CreateValueEditor(); + var baseEditor = base.CreateValueEditor(); - editor.Validators = new List { new DateTimeValidator() }; + return new DateValueEditor + { + View = baseEditor.View + }; + } + + /// + /// CUstom value editor so we can serialize with the correct date format (excluding time) + /// and includes the date validator + /// + private class DateValueEditor : ValueEditor + { + public DateValueEditor() + { + Validators = new List { new DateTimeValidator() }; + } + + public override string SerializeValue(object dbValue) + { + var date = dbValue.TryConvertTo(); + if (date.Success == false || date.Result == null) + { + return string.Empty; + } + //Dates will be formatted as yyyy-MM-dd + return date.Result.Value.ToString("yyyy-MM-dd"); + } - return editor; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs index 3ec863b7ab..55198a36a1 100644 --- a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Umbraco.Core; using Umbraco.Core.PropertyEditors; @@ -9,12 +10,18 @@ namespace Umbraco.Web.PropertyEditors { public DateTimePropertyEditor() { - _defaultPreVals = new Dictionary() ; + _defaultPreVals = new Dictionary + { + {"format", "yyyy-MM-dd HH:mm:ss"} + }; } - private IDictionary _defaultPreVals; + private IDictionary _defaultPreVals; - public override IDictionary DefaultPreValues + /// + /// Overridden because we ONLY support Date + Time format and we don't have pre-values in the db. + /// + public override IDictionary DefaultPreValues { get { return _defaultPreVals; } set { _defaultPreVals = value; } diff --git a/src/Umbraco.Web/PropertyEditors/DateTimeValidator.cs b/src/Umbraco.Web/PropertyEditors/DateTimeValidator.cs index 734e34622f..c1f7277a05 100644 --- a/src/Umbraco.Web/PropertyEditors/DateTimeValidator.cs +++ b/src/Umbraco.Web/PropertyEditors/DateTimeValidator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Umbraco.Core.PropertyEditors; +using Umbraco.Core; namespace Umbraco.Web.PropertyEditors { @@ -13,7 +14,7 @@ namespace Umbraco.Web.PropertyEditors public override IEnumerable Validate(string value, string preValues, PropertyEditor editor) { DateTime dt; - if (DateTime.TryParse(value, out dt) == false) + if (value.IsNullOrWhiteSpace() == false && DateTime.TryParse(value, out dt) == false) { yield return new ValidationResult(string.Format("The string value {0} cannot be parsed into a DateTime", value), new[]