diff --git a/src/Umbraco.Core/Models/PreValueCollection.cs b/src/Umbraco.Core/Models/PreValueCollection.cs
new file mode 100644
index 0000000000..154e4a58ad
--- /dev/null
+++ b/src/Umbraco.Core/Models/PreValueCollection.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+
+namespace Umbraco.Core.Models
+{
+ ///
+ /// Represents the pre-value data for a DataType
+ ///
+ ///
+ /// Due to the legacy nature of the data that can be stored for pre-values, we have this class which encapsulates the 2 different
+ /// ways that pre-values are stored: A string array or a Dictionary.
+ ///
+ /// Most legacy property editors won't support the dictionary format but new property editors should always use the dictionary format.
+ /// In order to get overrideable pre-values working we need a dictionary since we'll have to reference a pre-value by a key.
+ ///
+ public class PreValueCollection
+ {
+ private IDictionary _preValuesAsDictionary;
+ private IEnumerable _preValuesAsArray;
+ public IEnumerable PreValuesAsArray
+ {
+ get
+ {
+ if (_preValuesAsArray == null)
+ {
+ throw new InvalidOperationException("The current pre-value collection is dictionary based, use the PreValuesAsDictionary property instead");
+ }
+ return _preValuesAsArray;
+ }
+ set { _preValuesAsArray = value; }
+ }
+
+ public IDictionary PreValuesAsDictionary
+ {
+ get
+ {
+ if (_preValuesAsDictionary == null)
+ {
+ throw new InvalidOperationException("The current pre-value collection is array based, use the PreValuesAsArray property instead");
+ }
+ return _preValuesAsDictionary;
+ }
+ set { _preValuesAsDictionary = value; }
+ }
+
+ ///
+ /// Check if it is a dictionary based collection
+ ///
+ public bool IsDictionaryBased
+ {
+ get { return _preValuesAsDictionary != null; }
+ }
+
+ public PreValueCollection(IEnumerable preVals)
+ {
+ _preValuesAsArray = preVals;
+ }
+
+ public PreValueCollection(IDictionary preVals)
+ {
+ _preValuesAsDictionary = preVals;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/ObjectResolution/Resolution.cs b/src/Umbraco.Core/ObjectResolution/Resolution.cs
index d9e5977e4a..2c6dab4225 100644
--- a/src/Umbraco.Core/ObjectResolution/Resolution.cs
+++ b/src/Umbraco.Core/ObjectResolution/Resolution.cs
@@ -13,8 +13,9 @@ namespace Umbraco.Core.ObjectResolution
internal static class Resolution
{
private static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
+ private volatile static bool _isFrozen;
- ///
+ ///
/// Occurs when resolution is frozen.
///
/// Occurs only once, since resolution can be frozen only once.
@@ -23,12 +24,17 @@ namespace Umbraco.Core.ObjectResolution
///
/// Gets or sets a value indicating whether resolution of objects is frozen.
///
- public static bool IsFrozen { get; private set; }
-
- public static void EnsureIsFrozen()
+ public static bool IsFrozen
{
- if (!IsFrozen)
+ get { return _isFrozen; }
+ private set { _isFrozen = value; }
+ }
+
+ public static void EnsureIsFrozen()
+ {
+ if (!_isFrozen)
throw new InvalidOperationException("Resolution is not frozen, it is not yet possible to get values from it.");
+
}
///
@@ -40,7 +46,7 @@ namespace Umbraco.Core.ObjectResolution
get
{
IDisposable l = new WriteLock(_lock);
- if (Resolution.IsFrozen)
+ if (_isFrozen)
{
l.Dispose();
throw new InvalidOperationException("Resolution is frozen, it is not possible to configure it anymore.");
@@ -73,13 +79,13 @@ namespace Umbraco.Core.ObjectResolution
public DirtyBackdoor()
{
_lock = new WriteLock(_dirtyLock);
- _frozen = Resolution.IsFrozen;
- Resolution.IsFrozen = false;
+ _frozen = _isFrozen;
+ _isFrozen = false;
}
public void Dispose()
{
- Resolution.IsFrozen = _frozen;
+ _isFrozen = _frozen;
_lock.Dispose();
}
}
@@ -90,10 +96,10 @@ namespace Umbraco.Core.ObjectResolution
/// resolution is already frozen.
public static void Freeze()
{
- if (Resolution.IsFrozen)
+ if (_isFrozen)
throw new InvalidOperationException("Resolution is frozen. It is not possible to freeze it again.");
- IsFrozen = true;
+ _isFrozen = true;
if (Frozen != null)
Frozen(null, null);
}
@@ -104,7 +110,7 @@ namespace Umbraco.Core.ObjectResolution
/// To be used in unit tests.
internal static void Reset()
{
- IsFrozen = false;
+ _isFrozen = false;
Frozen = null;
}
}
diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs
index 650c41a613..3c23bc9991 100644
--- a/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/PropertyEditor.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
@@ -28,14 +29,23 @@ namespace Umbraco.Core.PropertyEditors
{
Id = Guid.Parse(att.Id);
Name = att.Name;
-
+
StaticallyDefinedValueEditor.ValueType = att.ValueType;
StaticallyDefinedValueEditor.View = att.EditorView;
StaticallyDefinedPreValueEditor.View = att.PreValueEditorView;
}
}
+ ///
+ /// These are assigned by default normally based on property editor attributes or manifest definitions,
+ /// developers have the chance to override CreateValueEditor if they don't want to use the pre-defined instance
+ ///
internal ValueEditor StaticallyDefinedValueEditor = null;
+
+ ///
+ /// These are assigned by default normally based on property editor attributes or manifest definitions,
+ /// developers have the chance to override CreatePreValueEditor if they don't want to use the pre-defined instance
+ ///
internal PreValueEditor StaticallyDefinedPreValueEditor = null;
///
@@ -62,6 +72,9 @@ namespace Umbraco.Core.PropertyEditors
get { return CreatePreValueEditor(); }
}
+ [JsonProperty("defaultConfig")]
+ 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
// it so they can perform custom operations on saving the data.
@@ -96,6 +109,48 @@ namespace Umbraco.Core.PropertyEditors
return StaticallyDefinedPreValueEditor;
}
+ ///
+ /// This can be used to re-format the currently saved pre-values that will be passed to the editor,
+ /// by default this returns the merged default and persisted pre-values.
+ ///
+ ///
+ /// The default/static pre-vals for the property editor
+ ///
+ ///
+ /// The persisted pre-vals for the property editor
+ ///
+ ///
+ ///
+ /// 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 ?
+ ///
+ public virtual IDictionary FormatPreValues(IDictionary defaultPreVals, PreValueCollection persistedPreVals)
+ {
+ if (defaultPreVals == null)
+ {
+ defaultPreVals = new Dictionary();
+ }
+
+ if (persistedPreVals.IsDictionaryBased)
+ {
+ //we just need to merge the dictionaries now, the persisted will replace default.
+ foreach (var item in persistedPreVals.PreValuesAsDictionary)
+ {
+ defaultPreVals[item.Key] = item.Value;
+ }
+ return defaultPreVals;
+ }
+
+ //it's an array so need to format it
+ var result = new Dictionary();
+ var asArray = persistedPreVals.PreValuesAsArray.ToArray();
+ for (var i = 0; i < asArray.Length; i++)
+ {
+ result.Add(i.ToInvariantString(), asArray[i]);
+ }
+ return result;
+ }
+
protected bool Equals(PropertyEditor other)
{
return Id.Equals(other.Id);
diff --git a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs
index 0cc3fe60a6..8f8f23a056 100644
--- a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs
@@ -129,10 +129,12 @@ namespace Umbraco.Core.PropertyEditors
valueType = typeof(string);
break;
case DataTypeDatabaseType.Integer:
- valueType = typeof(int);
+ //ensure these are nullable so we can return a null if required
+ valueType = typeof(int?);
break;
case DataTypeDatabaseType.Date:
- valueType = typeof(DateTime);
+ //ensure these are nullable so we can return a null if required
+ valueType = typeof(DateTime?);
break;
default:
throw new ArgumentOutOfRangeException();
@@ -184,6 +186,14 @@ namespace Umbraco.Core.PropertyEditors
//we can just ToString() any of these types
return dbValue.ToString();
case DataTypeDatabaseType.Date:
+ var s = dbValue as string;
+ if (s != null)
+ {
+ if (s.IsNullOrWhiteSpace())
+ {
+ return string.Empty;
+ }
+ }
//Dates will be formatted in 'o' format (otherwise known as xml format)
return dbValue.ToXmlString();
default:
diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs
index 68c0f308bd..3a2bc3a4f2 100644
--- a/src/Umbraco.Core/Services/DataTypeService.cs
+++ b/src/Umbraco.Core/Services/DataTypeService.cs
@@ -133,6 +133,22 @@ namespace Umbraco.Core.Services
}
}
+ ///
+ /// Returns the PreValueCollection for the specified data type
+ ///
+ ///
+ ///
+ internal PreValueCollection GetPreValuesCollectionByDataTypeId(int id)
+ {
+ using (var uow = _uowProvider.GetUnitOfWork())
+ {
+ var dtos = uow.Database.Fetch("WHERE datatypeNodeId = @Id", new { Id = id });
+ var list = dtos.Select(x => new Tuple(x.Id, x.Alias, x.SortOrder, x.Value)).ToList();
+
+ return PreValueConverter.ConvertToPreValuesCollection(list);
+ }
+ }
+
///
/// Gets a specific PreValue by its Id
///
@@ -327,5 +343,41 @@ namespace Umbraco.Core.Services
///
public static event TypedEventHandler> Saved;
#endregion
+
+ internal static class PreValueConverter
+ {
+ ///
+ /// Converts the tuple to a pre-value collection
+ ///
+ ///
+ ///
+ 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();
+
+ //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();
+ if (keys.Length == 1 && keys[0].IsNullOrWhiteSpace())
+ {
+ return new PreValueCollection(list.OrderBy(x => x.Item3).Select(x => x.Item4));
+ }
+
+ foreach (var item in list
+ .OrderBy(x => x.Item3) //we'll order them first so we maintain the order index in the dictionary
+ .GroupBy(x => x.Item2))
+ {
+ if (item.Count() > 1)
+ {
+ //if there's more than 1 item per key, then it cannot be a dictionary, just return the array
+ return new PreValueCollection(list.OrderBy(x => x.Item3).Select(x => x.Item4));
+ }
+
+ dictionary.Add(item.Key, item.First().Item4);
+ }
+
+ return new PreValueCollection(dictionary);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index ae5ccb1e60..0d67bbbdae 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -225,6 +225,7 @@
+
diff --git a/src/Umbraco.Tests/AngularIntegration/ContentModelSerializationTests.cs b/src/Umbraco.Tests/AngularIntegration/ContentModelSerializationTests.cs
index d33b9045e5..cee6bf00f8 100644
--- a/src/Umbraco.Tests/AngularIntegration/ContentModelSerializationTests.cs
+++ b/src/Umbraco.Tests/AngularIntegration/ContentModelSerializationTests.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using NUnit.Framework;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using Umbraco.Core;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Tests.AngularIntegration
@@ -29,7 +30,7 @@ namespace Umbraco.Tests.AngularIntegration
Label = "Property " + propertyIndex,
Id = propertyIndex,
Value = "value" + propertyIndex,
- Config = new[] {"config" + propertyIndex},
+ Config = new Dictionary {{ propertyIndex.ToInvariantString(), "value" }},
Description = "Description " + propertyIndex,
View = "~/Views/View" + propertyIndex,
HideLabel = false
@@ -68,7 +69,7 @@ namespace Umbraco.Tests.AngularIntegration
Assert.AreEqual("Property " + prop, jObject["tabs"][tab]["properties"][prop]["label"].ToString());
Assert.AreEqual(prop, jObject["tabs"][tab]["properties"][prop]["id"].Value());
Assert.AreEqual("value" + prop, jObject["tabs"][tab]["properties"][prop]["value"].ToString());
- Assert.AreEqual("[\"config" + prop + "\"]", jObject["tabs"][tab]["properties"][prop]["config"].ToString(Formatting.None));
+ Assert.AreEqual("{\"" + prop + "\":\"value\"}", jObject["tabs"][tab]["properties"][prop]["config"].ToString(Formatting.None));
Assert.AreEqual("Description " + prop, jObject["tabs"][tab]["properties"][prop]["description"].ToString());
Assert.AreEqual(false, jObject["tabs"][tab]["properties"][prop]["hideLabel"].Value());
}
diff --git a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs
index b951380698..44d3149e85 100644
--- a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs
+++ b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs
@@ -31,8 +31,8 @@ namespace Umbraco.Tests.Models.Mapping
protected override void FreezeResolution()
{
- PropertyEditorResolver.Current = new PropertyEditorResolver(
- () => new List {typeof (TestPropertyEditor)});
+ //PropertyEditorResolver.Current = new PropertyEditorResolver(
+ // () => new List {typeof (TestPropertyEditor)});
base.FreezeResolution();
}
@@ -96,6 +96,13 @@ namespace Umbraco.Tests.Models.Mapping
{
var contentType = MockedContentTypes.CreateSimpleContentType();
var content = MockedContent.CreateSimpleContent(contentType);
+ //need ids for tabs
+ var id = 1;
+ foreach (var g in content.PropertyGroups)
+ {
+ g.Id = id;
+ id++;
+ }
var result = Mapper.Map(content);
@@ -131,6 +138,13 @@ namespace Umbraco.Tests.Models.Mapping
p.Id = idSeed;
idSeed++;
}
+ //need ids for tabs
+ var id = 1;
+ foreach (var g in content.PropertyGroups)
+ {
+ g.Id = id;
+ id++;
+ }
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
//ensure that nothing is marked as dirty
@@ -145,7 +159,7 @@ namespace Umbraco.Tests.Models.Mapping
}
Assert.AreEqual(content.PropertyGroups.Count(), result.Tabs.Count() - 1);
Assert.IsTrue(result.Tabs.Any(x => x.Label == "Generic properties"));
- Assert.AreEqual(2, result.Tabs.Where(x => x.Label == "Generic properties").SelectMany(x => x.Properties).Count());
+ Assert.AreEqual(2, result.Tabs.Where(x => x.Label == "Generic properties").SelectMany(x => x.Properties.Where(p => p.Alias.StartsWith("_umb_") == false)).Count());
}
#region Assertions
@@ -158,10 +172,11 @@ namespace Umbraco.Tests.Models.Mapping
var pDto = result.Properties.SingleOrDefault(x => x.Alias == p.Alias);
Assert.IsNotNull(pDto);
- pDto.Alias = p.Alias;
- pDto.Description = p.PropertyType.Description;
- pDto.Label = p.PropertyType.Name;
- pDto.Config = applicationContext.Services.DataTypeService.GetPreValuesByDataTypeId(p.PropertyType.DataTypeDefinitionId);
+
+ //pDto.Alias = p.Alias;
+ //pDto.Description = p.PropertyType.Description;
+ //pDto.Label = p.PropertyType.Name;
+ //pDto.Config = applicationContext.Services.DataTypeService.GetPreValuesByDataTypeId(p.PropertyType.DataTypeDefinitionId);
}
@@ -176,7 +191,7 @@ namespace Umbraco.Tests.Models.Mapping
Assert.AreEqual(content.UpdateDate, result.UpdateDate);
Assert.AreEqual(content.CreateDate, result.CreateDate);
Assert.AreEqual(content.Name, result.Name);
- Assert.AreEqual(content.Properties.Count(), result.Properties.Count());
+ Assert.AreEqual(content.Properties.Count(), result.Properties.Count(x => x.Alias.StartsWith("_umb_") == false));
}
private void AssertBasicProperty(ContentItemBasic result, Property p)
diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs
index 4e5cfe56dd..989895f50d 100644
--- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs
+++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs
@@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
-using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.PropertyEditors
{
- [TestFixture]
+ [TestFixture]
public class PropertyEditorValueConverterTests
{
[TestCase("2012-11-10", true)]
diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs
new file mode 100644
index 0000000000..730dd4ad56
--- /dev/null
+++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs
@@ -0,0 +1,72 @@
+using System;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Tests.PropertyEditors
+{
+ [TestFixture]
+ public class PropertyEditorValueEditorTests
+ {
+ [TestCase("STRING", "hello", "hello")]
+ [TestCase("TEXT", "hello", "hello")]
+ [TestCase("INT", "123", 123)]
+ [TestCase("INTEGER", "123", 123)]
+ [TestCase("INTEGER", "", null)] //test empty string for int
+ [TestCase("DATETIME", "", null)] //test empty string for date
+ public void Value_Editor_Can_Convert_To_Clr_Type(string valueType, string val, object expected)
+ {
+ var valueEditor = new ValueEditor
+ {
+ ValueType = valueType
+ };
+
+ var result = valueEditor.TryConvertValueToCrlType(val);
+ Assert.IsTrue(result.Success);
+ Assert.AreEqual(expected, result.Result);
+ }
+
+ [Test]
+ public void Value_Editor_Can_Convert_To_Date_Clr_Type()
+ {
+ var valueEditor = new ValueEditor
+ {
+ ValueType = "DATE"
+ };
+
+ var result = valueEditor.TryConvertValueToCrlType("2010-02-05");
+ Assert.IsTrue(result.Success);
+ Assert.AreEqual(new DateTime(2010, 2, 5), result.Result);
+ }
+
+ [TestCase("STRING", "hello", "hello")]
+ [TestCase("TEXT", "hello", "hello")]
+ [TestCase("INT", 123, "123")]
+ [TestCase("INTEGER", 123, "123")]
+ [TestCase("INTEGER", "", "")] //test empty string for int
+ [TestCase("DATETIME", "", "")] //test empty string for date
+ public void Value_Editor_Can_Serialize_Value(string valueType, object val, string expected)
+ {
+ var valueEditor = new ValueEditor
+ {
+ ValueType = valueType
+ };
+
+ var result = valueEditor.SerializeValue(val);
+ Assert.AreEqual(expected, result);
+ }
+
+ [Test]
+ public void Value_Editor_Can_Serialize_Date_Value()
+ {
+ var now = DateTime.Now;
+ var valueEditor = new ValueEditor
+ {
+ ValueType = "DATE"
+ };
+
+ var result = valueEditor.SerializeValue(now);
+ Assert.AreEqual(now.ToXmlString(), result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Services/DataTypeServiceTests.cs b/src/Umbraco.Tests/Services/DataTypeServiceTests.cs
index 31b0489949..259c28ba25 100644
--- a/src/Umbraco.Tests/Services/DataTypeServiceTests.cs
+++ b/src/Umbraco.Tests/Services/DataTypeServiceTests.cs
@@ -23,6 +23,8 @@ namespace Umbraco.Tests.Services
base.TearDown();
}
+
+
[Test]
public void DataTypeService_Can_Persist_New_DataTypeDefinition()
{
diff --git a/src/Umbraco.Tests/Services/PreValueConverterTests.cs b/src/Umbraco.Tests/Services/PreValueConverterTests.cs
new file mode 100644
index 0000000000..d02544052b
--- /dev/null
+++ b/src/Umbraco.Tests/Services/PreValueConverterTests.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using Umbraco.Core.Services;
+
+namespace Umbraco.Tests.Services
+{
+ [TestFixture]
+ public class PreValueConverterTests
+ {
+ [Test]
+ public void Can_Convert_To_Dictionary_Pre_Value_Collection()
+ {
+ var list = new List>
+ {
+ new Tuple(10, "key1", 0, "value1"),
+ new Tuple(11, "key2", 3, "value2"),
+ new Tuple(12, "key3", 2, "value3"),
+ new Tuple(13, "key4", 1, "value4")
+ };
+
+ var result = DataTypeService.PreValueConverter.ConvertToPreValuesCollection(list);
+
+ Assert.Throws(() =>
+ {
+ var blah = result.PreValuesAsArray;
+ });
+
+ Assert.AreEqual(4, result.PreValuesAsDictionary.Count);
+ Assert.AreEqual("key1", result.PreValuesAsDictionary.ElementAt(0).Key);
+ Assert.AreEqual("key4", result.PreValuesAsDictionary.ElementAt(1).Key);
+ Assert.AreEqual("key3", result.PreValuesAsDictionary.ElementAt(2).Key);
+ Assert.AreEqual("key2", result.PreValuesAsDictionary.ElementAt(3).Key);
+
+ }
+
+ [Test]
+ public void Can_Convert_To_Array_Pre_Value_Collection_When_Empty_Key()
+ {
+ var list = new List>
+ {
+ new Tuple(10, "", 0, "value1"),
+ new Tuple(11, "", 3, "value2"),
+ new Tuple(12, "", 2, "value3"),
+ new Tuple(13, "", 1, "value4")
+ };
+
+ var result = DataTypeService.PreValueConverter.ConvertToPreValuesCollection(list);
+
+ Assert.Throws(() =>
+ {
+ var blah = result.PreValuesAsDictionary;
+ });
+
+ Assert.AreEqual(4, result.PreValuesAsArray.Count());
+ Assert.AreEqual("value1", result.PreValuesAsArray.ElementAt(0));
+ Assert.AreEqual("value4", result.PreValuesAsArray.ElementAt(1));
+ Assert.AreEqual("value3", result.PreValuesAsArray.ElementAt(2));
+ Assert.AreEqual("value2", result.PreValuesAsArray.ElementAt(3));
+
+ }
+
+ [Test]
+ public void Can_Convert_To_Array_Pre_Value_Collection()
+ {
+ var list = new List>
+ {
+ new Tuple(10, "key1", 0, "value1"),
+ new Tuple(11, "key1", 3, "value2"),
+ new Tuple(12, "key3", 2, "value3"),
+ new Tuple(13, "key4", 1, "value4")
+ };
+
+ var result = DataTypeService.PreValueConverter.ConvertToPreValuesCollection(list);
+
+ Assert.Throws(() =>
+ {
+ var blah = result.PreValuesAsDictionary;
+ });
+
+ Assert.AreEqual(4, result.PreValuesAsArray.Count());
+ Assert.AreEqual("value1", result.PreValuesAsArray.ElementAt(0));
+ Assert.AreEqual("value4", result.PreValuesAsArray.ElementAt(1));
+ Assert.AreEqual("value3", result.PreValuesAsArray.ElementAt(2));
+ Assert.AreEqual("value2", result.PreValuesAsArray.ElementAt(3));
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 29abbe2015..a05aeee774 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -55,7 +55,7 @@
False
..\packages\AutoMapper.2.2.1\lib\net40\AutoMapper.dll
-
+
False
..\packages\Examine.0.1.52.2941\lib\Examine.dll
@@ -213,8 +213,10 @@
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js
index e349ea81d4..3311d5005e 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js
@@ -33,8 +33,8 @@ angular.module("umbraco.directives")
template: '' +
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 3c1b9e3372..10f1a715ee 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,8 +1,11 @@
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index c64e035b79..e18ca1c529 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -195,7 +195,9 @@ namespace Umbraco.Web.Editors
contentItem.PersistedContent.ExpireDate = contentItem.ExpireDate;
contentItem.PersistedContent.ReleaseDate = contentItem.ReleaseDate;
//only set the template if it didn't change
- if (contentItem.PersistedContent.Template.Alias != contentItem.TemplateAlias)
+ var templateChanged = (contentItem.PersistedContent.Template == null && contentItem.TemplateAlias.IsNullOrWhiteSpace() == false)
+ || (contentItem.PersistedContent.Template != null && contentItem.PersistedContent.Template.Alias != contentItem.TemplateAlias);
+ if (templateChanged)
{
var template = Services.FileService.GetTemplate(contentItem.TemplateAlias);
if (template == null)
diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs
index 57bfcbe006..df1182ba9b 100644
--- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs
@@ -1,5 +1,4 @@
using System;
-using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using System.Web.Http;
@@ -32,20 +31,4 @@ namespace Umbraco.Web.Models.ContentEditing
public string[] Urls { get; set; }
}
-
- [DataContract(Name = "template", Namespace = "")]
- public class TemplateBasic
- {
- [DataMember(Name = "id", IsRequired = true)]
- [Required]
- public int Id { get; set; }
-
- [DataMember(Name = "name", IsRequired = true)]
- [Required(AllowEmptyStrings = false)]
- public string Name { get; set; }
-
- [DataMember(Name = "alias", IsRequired = true)]
- [Required(AllowEmptyStrings = false)]
- public string Alias { get; set; }
- }
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs
index ac01601e27..a087840f34 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 IEnumerable Config { get; set; }
+ public IDictionary Config { get; set; }
[DataMember(Name = "hideLabel")]
public bool HideLabel { get; set; }
diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs
index 42782b1b14..17f4f39680 100644
--- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs
@@ -12,7 +12,6 @@ namespace Umbraco.Web.Models.ContentEditing
public IDataTypeDefinition DataType { get; set; }
public string Label { get; set; }
public string Description { get; set; }
- public PropertyEditor PropertyEditor { get; set; }
public bool IsRequired { get; set; }
public string ValidationRegExp { get; set; }
}
diff --git a/src/Umbraco.Web/Models/ContentEditing/TemplateBasic.cs b/src/Umbraco.Web/Models/ContentEditing/TemplateBasic.cs
new file mode 100644
index 0000000000..dbb3d6c8bd
--- /dev/null
+++ b/src/Umbraco.Web/Models/ContentEditing/TemplateBasic.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.DataAnnotations;
+using System.Runtime.Serialization;
+
+namespace Umbraco.Web.Models.ContentEditing
+{
+ [DataContract(Name = "template", Namespace = "")]
+ public class TemplateBasic
+ {
+ [DataMember(Name = "id", IsRequired = true)]
+ [Required]
+ public int Id { get; set; }
+
+ [DataMember(Name = "name", IsRequired = true)]
+ [Required(AllowEmptyStrings = false)]
+ public string Name { get; set; }
+
+ [DataMember(Name = "alias", IsRequired = true)]
+ [Required(AllowEmptyStrings = false)]
+ public string Alias { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
index ac8bb18b8b..32313cf75e 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
@@ -14,6 +14,11 @@ namespace Umbraco.Web.Models.Mapping
internal class ContentPropertyBasicConverter : TypeConverter
where T : ContentPropertyBasic, new()
{
+ ///
+ /// Assigns the PropertyEditor, Id, Alias and Value to the property
+ ///
+ ///
+ ///
protected override T ConvertCore(Property property)
{
var editor = PropertyEditorResolver.Current.GetById(property.PropertyType.DataTypeId);
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
index c51ac48ae5..e149b1c5ef 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
@@ -1,6 +1,8 @@
-using Umbraco.Core;
+using System.Linq;
+using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
+using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models.Mapping
@@ -25,7 +27,13 @@ namespace Umbraco.Web.Models.Mapping
display.Alias = originalProp.Alias;
display.Description = originalProp.PropertyType.Description;
display.Label = originalProp.PropertyType.Name;
- display.Config = _applicationContext.Services.DataTypeService.GetPreValuesByDataTypeId(originalProp.PropertyType.DataTypeDefinitionId);
+ var dataTypeService = (DataTypeService) _applicationContext.Services.DataTypeService;
+
+ var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(originalProp.PropertyType.DataTypeDefinitionId);
+
+ //let the property editor format the pre-values
+ display.Config = display.PropertyEditor.FormatPreValues(display.PropertyEditor.DefaultPreValues, preVals);
+
if (display.PropertyEditor == null)
{
//if there is no property editor it means that it is a legacy data type
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
index 9fe38cc988..297406e10d 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
@@ -23,11 +23,9 @@ namespace Umbraco.Web.Models.Mapping
propertyDto.IsRequired = originalProperty.PropertyType.Mandatory;
propertyDto.ValidationRegExp = originalProperty.PropertyType.ValidationRegExp;
- propertyDto.Alias = originalProperty.Alias;
propertyDto.Description = originalProperty.PropertyType.Description;
propertyDto.Label = originalProperty.PropertyType.Name;
propertyDto.DataType = _applicationContext.Services.DataTypeService.GetDataTypeDefinitionById(originalProperty.PropertyType.DataTypeDefinitionId);
- propertyDto.PropertyEditor = PropertyEditorResolver.Current.GetById(originalProperty.PropertyType.DataTypeId);
return propertyDto;
}
diff --git a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs
new file mode 100644
index 0000000000..06458928f0
--- /dev/null
+++ b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using Newtonsoft.Json.Linq;
+using Umbraco.Core;
+using Umbraco.Core.Models;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Web.PropertyEditors
+{
+ [PropertyEditor(Constants.PropertyEditors.Date, "Date", "datepicker", ValueType = "DATE")]
+ public class DatePropertyEditor : PropertyEditor
+ {
+ protected override ValueEditor CreateValueEditor()
+ {
+ var editor = base.CreateValueEditor();
+
+ editor.Validators = new List { new DateTimeValidator() };
+
+ return editor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs
new file mode 100644
index 0000000000..3ec863b7ab
--- /dev/null
+++ b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using Umbraco.Core;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Web.PropertyEditors
+{
+ [PropertyEditor(Constants.PropertyEditors.DateTime, "Date/Time", "datepicker", ValueType = "DATETIME")]
+ public class DateTimePropertyEditor : PropertyEditor
+ {
+ public DateTimePropertyEditor()
+ {
+ _defaultPreVals = new Dictionary() ;
+ }
+
+ private IDictionary _defaultPreVals;
+
+ public override IDictionary DefaultPreValues
+ {
+ get { return _defaultPreVals; }
+ set { _defaultPreVals = value; }
+ }
+
+ protected override ValueEditor CreateValueEditor()
+ {
+ var editor = base.CreateValueEditor();
+
+ editor.Validators = new List { new DateTimeValidator() };
+
+ return editor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/PropertyEditors/DateTimeValidator.cs b/src/Umbraco.Web/PropertyEditors/DateTimeValidator.cs
new file mode 100644
index 0000000000..734e34622f
--- /dev/null
+++ b/src/Umbraco.Web/PropertyEditors/DateTimeValidator.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Web.PropertyEditors
+{
+ ///
+ /// Used to validate if the value is a valid date/time
+ ///
+ internal class DateTimeValidator : ValidatorBase
+ {
+ public override IEnumerable Validate(string value, string preValues, PropertyEditor editor)
+ {
+ DateTime dt;
+ if (DateTime.TryParse(value, out dt) == false)
+ {
+ yield return new ValidationResult(string.Format("The string value {0} cannot be parsed into a DateTime", value),
+ new[]
+ {
+ //we only store a single value for this editor so the 'member' or 'field'
+ // we'll associate this error with will simply be called 'value'
+ "value"
+ });
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 40cdd91586..168657080a 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -299,7 +299,11 @@
+
+
+
+
diff --git a/src/umbraco.businesslogic/ui.cs b/src/umbraco.businesslogic/ui.cs
index cfb0a1832d..4416ed2451 100644
--- a/src/umbraco.businesslogic/ui.cs
+++ b/src/umbraco.businesslogic/ui.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
@@ -308,27 +309,35 @@ namespace umbraco
{
var cacheKey = "uitext_" + language;
- return ApplicationContext.Current.ApplicationCache.GetCacheItem(
- cacheKey,
- CacheItemPriority.Default,
- new CacheDependency(IOHelper.MapPath(UmbracoPath + "/config/lang/" + language + ".xml")),
- () =>
- {
- using (var langReader = new XmlTextReader(IOHelper.MapPath(UmbracoPath + "/config/lang/" + language + ".xml")))
+ var file = IOHelper.MapPath(UmbracoPath + "/config/lang/" + language + ".xml");
+ if (File.Exists(file))
+ {
+ return ApplicationContext.Current.ApplicationCache.GetCacheItem(
+ cacheKey,
+ CacheItemPriority.Default,
+ new CacheDependency(IOHelper.MapPath(UmbracoPath + "/config/lang/" + language + ".xml")),
+ () =>
{
- try
+ using (var langReader = new XmlTextReader(IOHelper.MapPath(UmbracoPath + "/config/lang/" + language + ".xml")))
{
- var langFile = new XmlDocument();
- langFile.Load(langReader);
- return langFile;
+ try
+ {
+ var langFile = new XmlDocument();
+ langFile.Load(langReader);
+ return langFile;
+ }
+ catch (Exception e)
+ {
+ LogHelper.Error("Error reading umbraco language xml source (" + language + ")", e);
+ return null;
+ }
}
- catch (Exception e)
- {
- LogHelper.Error("Error reading umbraco language xml source (" + language + ")", e);
- return null;
- }
- }
- });
+ });
+ }
+ else
+ {
+ return null;
+ }
}