Merge branch '7.0.0' of https://github.com/umbraco/Umbraco-CMS into 7.0.0

This commit is contained in:
perploug
2013-08-22 14:46:51 +02:00
21 changed files with 268 additions and 109 deletions

View File

@@ -16,7 +16,7 @@ namespace Umbraco.Core.Models
/// </remarks>
public class PreValueCollection
{
private IDictionary<string, object> _preValuesAsDictionary;
private IDictionary<string, string> _preValuesAsDictionary;
private IEnumerable<string> _preValuesAsArray;
public IEnumerable<string> PreValuesAsArray
{
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Models
set { _preValuesAsArray = value; }
}
public IDictionary<string, object> PreValuesAsDictionary
public IDictionary<string, string> PreValuesAsDictionary
{
get
{
@@ -57,12 +57,12 @@ namespace Umbraco.Core.Models
_preValuesAsArray = preVals;
}
public PreValueCollection(IDictionary<string, object> preVals)
public PreValueCollection(IDictionary<string, string> preVals)
{
_preValuesAsDictionary = preVals;
}
internal static IDictionary<string, object> AsDictionary(PreValueCollection persistedPreVals)
internal static IDictionary<string, string> AsDictionary(PreValueCollection persistedPreVals)
{
if (persistedPreVals.IsDictionaryBased)
{
@@ -70,7 +70,7 @@ namespace Umbraco.Core.Models
}
//it's an array so need to format it
var result = new Dictionary<string, object>();
var result = new Dictionary<string, string>();
var asArray = persistedPreVals.PreValuesAsArray.ToArray();
for (var i = 0; i < asArray.Length; i++)
{

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Models;
namespace Umbraco.Core.PropertyEditors
{
@@ -29,5 +30,67 @@ namespace Umbraco.Core.PropertyEditors
[JsonProperty("fields")]
public IEnumerable<PreValueField> Fields { get; set; }
/// <summary>
/// A method to format the posted values from the editor to the values to be persisted
/// </summary>
/// <param name="editorValue"></param>
/// <param name="currentValue">
/// The current value that has been persisted to the database for this pre-value editor. This value may be usesful for
/// how the value then get's deserialized again to be re-persisted. In most cases it will probably not be used.
/// </param>
/// <returns></returns>
/// <remarks>
/// By default this will just return the Posted editorValue.
///
/// This can be overridden if perhaps you have a comma delimited string posted value but want to convert those to individual rows, or to convert
/// a json structure to multiple rows.
/// </remarks>
public virtual IDictionary<string, string> FormatDataForPersistence(IDictionary<string, string> editorValue, PreValueCollection currentValue)
{
return editorValue;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="defaultPreVals">
/// The default/static pre-vals for the property editor
/// </param>
/// <param name="persistedPreVals">
/// The persisted pre-vals for the property editor
/// </param>
/// <returns></returns>
/// <remarks>
/// 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 convert the string values to strongly typed values in json (i.e. booleans)
/// </remarks>
public virtual IDictionary<string, object> FormatDataForEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
{
if (defaultPreVals == null)
{
defaultPreVals = new Dictionary<string, object>();
}
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<string, object>();
var asArray = persistedPreVals.PreValuesAsArray.ToArray();
for (var i = 0; i < asArray.Length; i++)
{
result.Add(i.ToInvariantString(), asArray[i]);
}
return result;
}
}
}

View File

@@ -8,6 +8,11 @@ namespace Umbraco.Core.PropertyEditors
/// </summary>
public class PreValueField
{
public PreValueField()
{
Validators = new List<ValidatorBase>();
}
/// <summary>
/// The name to display for this pre-value field
/// </summary>

View File

@@ -112,49 +112,7 @@ namespace Umbraco.Core.PropertyEditors
}
return StaticallyDefinedPreValueEditor;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="defaultPreVals">
/// The default/static pre-vals for the property editor
/// </param>
/// <param name="persistedPreVals">
/// The persisted pre-vals for the property editor
/// </param>
/// <returns></returns>
/// <remarks>
/// 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 convert the string values to strongly typed values in json (i.e. booleans)
/// </remarks>
public virtual IDictionary<string, object> FormatPreValues(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
{
if (defaultPreVals == null)
{
defaultPreVals = new Dictionary<string, object>();
}
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<string, object>();
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);

View File

@@ -161,7 +161,7 @@ namespace Umbraco.Core.PropertyEditors
/// If overridden then the object returned must match the type supplied in the ValueType, otherwise persisting the
/// value to the DB will fail when it tries to validate the value type.
/// </remarks>
public virtual object DeserializeValue(ContentPropertyData editorValue, object currentValue)
public virtual object FormatDataForPersistence(ContentPropertyData editorValue, object currentValue)
{
var result = TryConvertValueToCrlType(editorValue.Value);
if (result.Success == false)
@@ -177,7 +177,7 @@ namespace Umbraco.Core.PropertyEditors
/// </summary>
/// <param name="dbValue"></param>
/// <returns></returns>
public virtual string SerializeValue(object dbValue)
public virtual string FormatDataForEditor(object dbValue)
{
if (dbValue == null) return string.Empty;

View File

@@ -443,7 +443,7 @@ namespace Umbraco.Core.Services
internal static PreValueCollection ConvertToPreValuesCollection(IEnumerable<Tuple<int, string, int, string>> list)
{
//now we need to determine if they are dictionary based, otherwise they have to be array based
var dictionary = new Dictionary<string, object>();
var dictionary = new Dictionary<string, string>();
//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();

View File

@@ -52,7 +52,7 @@ namespace Umbraco.Tests.PropertyEditors
ValueType = valueType
};
var result = valueEditor.SerializeValue(val);
var result = valueEditor.FormatDataForEditor(val);
Assert.AreEqual(expected, result);
}
@@ -65,7 +65,7 @@ namespace Umbraco.Tests.PropertyEditors
ValueType = "DATE"
};
var result = valueEditor.SerializeValue(now);
var result = valueEditor.FormatDataForEditor(now);
Assert.AreEqual(now.ToXmlString<DateTime>(), result);
}
}

View File

@@ -7,14 +7,18 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
return {
getPreValues: function (editorId) {
getPreValues: function (editorId, dataTypeId) {
if (!dataTypeId) {
dataTypeId = -1;
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"dataTypeApiBaseUrl",
"GetPreValues",
[{ editorId: editorId }])),
[{ editorId: editorId }, { dataTypeId: dataTypeId }])),
'Failed to retreive pre values for editor id ' + editorId);
},

View File

@@ -69,7 +69,8 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc
//when the value changes, we need to dynamically load in the new editor
if (newVal !== null && newVal !== undefined && newVal != oldVal) {
//we are editing so get the content item from the server
dataTypeResource.getPreValues(newVal)
var currDataTypeId = $routeParams.create ? undefined : $routeParams.id;
dataTypeResource.getPreValues(newVal, currDataTypeId)
.then(function (data) {
$scope.preValuesLoaded = true;
$scope.content.preValues = data;

View File

@@ -1,4 +1,5 @@
<div>
Hello world
I will finish this tomorrow.
<!--<input type="text" ng-model="model.value" />-->
</div>

View File

@@ -107,7 +107,7 @@ namespace Umbraco.Web.Editors
//don't persist any bound value if the editor is readonly
if (valueEditor.IsReadOnly == false)
{
dboProperty.Value = p.PropertyEditor.ValueEditor.DeserializeValue(data, dboProperty.Value);
dboProperty.Value = p.PropertyEditor.ValueEditor.FormatDataForPersistence(data, dboProperty.Value);
}
}

View File

@@ -5,6 +5,7 @@ using System.Net;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
@@ -54,8 +55,9 @@ namespace Umbraco.Web.Editors
/// Returns the pre-values for the specified property editor
/// </summary>
/// <param name="editorId"></param>
/// <param name="dataTypeId">The data type id for the pre-values, -1 if it is a new data type</param>
/// <returns></returns>
public IEnumerable<PreValueFieldDisplay> GetPreValues(Guid editorId)
public IEnumerable<PreValueFieldDisplay> GetPreValues(Guid editorId, int dataTypeId = -1)
{
var propEd = PropertyEditorResolver.Current.GetById(editorId);
if (propEd == null)
@@ -63,6 +65,29 @@ namespace Umbraco.Web.Editors
throw new InvalidOperationException("Could not find property editor with id " + editorId);
}
if (dataTypeId == -1)
{
//this is a new data type, so just return the field editors, there are no values yet
return propEd.PreValueEditor.Fields.Select(Mapper.Map<PreValueFieldDisplay>);
}
//we have a data type associated
var dataType = Services.DataTypeService.GetDataTypeDefinitionById(dataTypeId);
if (dataType == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
//now, lets check if the data type has the current editor selected, if that is true
//we will need to wire up it's saved values. Otherwise it's an existing data type
//that is changing it's underlying property editor, in which case there's no values.
if (dataType.ControlId == editorId)
{
//this is the currently assigned pre-value editor, return with values.
return Mapper.Map<IDataTypeDefinition, IEnumerable<PreValueFieldDisplay>>(dataType);
}
//return the pre value display without values
return propEd.PreValueEditor.Fields.Select(Mapper.Map<PreValueFieldDisplay>);
}
@@ -80,7 +105,23 @@ namespace Umbraco.Web.Editors
//finally we need to save the data type and it's pre-vals
var dtService = (DataTypeService) ApplicationContext.Services.DataTypeService;
var preVals = Mapper.Map<PreValueCollection>(dataType.PreValues);
//TODO: Check if the property editor has changed, if it has ensure we don't pass the
// existing values to the new property editor!
//get the prevalues, current and new
var preValDictionary = dataType.PreValues.ToDictionary(x => x.Key, x => x.Value);
var currVal = ((DataTypeService) Services.DataTypeService).GetPreValuesCollectionByDataTypeId(dataType.PersistedDataType.Id);
//we need to allow for the property editor to deserialize the prevalues
var formattedVal = dataType.PropertyEditor.PreValueEditor.FormatDataForPersistence(
preValDictionary,
currVal);
//create the pre-value collection to be saved
var preVals = new PreValueCollection(formattedVal.ToDictionary(x => x.Key, x => x.Value));
//save the data type
dtService.SaveDataTypeAndPreValues(dataType.PersistedDataType, preVals, (int)Security.CurrentUser.Id);
var display = Mapper.Map<IDataTypeDefinition, DataTypeDisplay>(dataType.PersistedDataType);

View File

@@ -42,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping
var result = new T
{
Id = property.Id,
Value = editor.ValueEditor.SerializeValue(property.Value),
Value = editor.ValueEditor.FormatDataForEditor(property.Value),
Alias = property.Alias
};

View File

@@ -9,7 +9,7 @@ using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models.Mapping
{
/// <summary>
/// Creates a ContentPropertyDto from a Property
/// Creates a ContentPropertyDisplay from a Property
/// </summary>
internal class ContentPropertyDisplayConverter : ContentPropertyBasicConverter<ContentPropertyDisplay>
{
@@ -35,16 +35,15 @@ namespace Umbraco.Web.Models.Mapping
if (display.PropertyEditor == null)
{
display.Config = PreValueCollection.AsDictionary(preVals);
//display.Config = PreValueCollection.AsDictionary(preVals);
//if there is no property editor it means that it is a legacy data type
// we cannot support editing with that so we'll just render the readonly value view.
display.View = GlobalSettings.Path.EnsureEndsWith('/') +
"views/propertyeditors/readonlyvalue/readonlyvalue.html";
display.View = "views/propertyeditors/readonlyvalue/readonlyvalue.html";
}
else
{
//let the property editor format the pre-values
display.Config = display.PropertyEditor.FormatPreValues(display.PropertyEditor.DefaultPreValues, preVals);
display.Config = display.PropertyEditor.PreValueEditor.FormatDataForEditor(display.PropertyEditor.DefaultPreValues, preVals);
display.View = display.PropertyEditor.ValueEditor.View;
}

View File

@@ -24,6 +24,7 @@ namespace Umbraco.Web.Models.Mapping
config.CreateMap<PropertyEditor, PropertyEditorBasic>()
.ForMember(basic => basic.EditorId, expression => expression.MapFrom(editor => editor.Id));
//just maps the standard properties, does not map the value!
config.CreateMap<PreValueField, PreValueFieldDisplay>();
config.CreateMap<IDataTypeDefinition, DataTypeDisplay>()
@@ -33,15 +34,20 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.SelectedEditor, expression => expression.MapFrom(
definition => definition.ControlId == Guid.Empty ? null : (Guid?) definition.ControlId));
//gets a list of PreValueFieldDisplay objects from the data type definition
config.CreateMap<IDataTypeDefinition, IEnumerable<PreValueFieldDisplay>>()
.ConvertUsing(definition =>
{
var resolver = new PreValueDisplayResolver(lazyDataTypeService);
return resolver.Convert(definition);
});
config.CreateMap<DataTypeSave, IDataTypeDefinition>()
.ConstructUsing(save => new DataTypeDefinition(-1, save.SelectedEditor) {CreateDate = DateTime.Now})
.ForMember(definition => definition.ControlId, expression => expression.MapFrom(save => save.SelectedEditor))
.ForMember(definition => definition.ParentId, expression => expression.MapFrom(save => -1))
.ForMember(definition => definition.DatabaseType, expression => expression.ResolveUsing<DatabaseTypeResolver>());
config.CreateMap<IEnumerable<PreValueFieldSave>, PreValueCollection>()
.ConstructUsing(
saves => new PreValueCollection(saves.ToDictionary(x => x.Key, x => (object) x.Value)));
}
}
}

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Web.Models.Mapping
_dataTypeService = dataTypeService;
}
protected override IEnumerable<PreValueFieldDisplay> ResolveCore(IDataTypeDefinition source)
internal IEnumerable<PreValueFieldDisplay> Convert(IDataTypeDefinition source)
{
PropertyEditor propEd = null;
if (source.ControlId != Guid.Empty)
@@ -29,20 +29,25 @@ namespace Umbraco.Web.Models.Mapping
if (propEd == null)
{
throw new InvalidOperationException("Could not find property editor with id " + source.ControlId);
}
}
}
var dataTypeService = (DataTypeService) _dataTypeService.Value;
//set up the defaults
var dataTypeService = (DataTypeService)_dataTypeService.Value;
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(source.Id);
var dictionaryVals = PreValueCollection.AsDictionary(preVals);
IDictionary<string, object> dictionaryVals = PreValueCollection.AsDictionary(preVals).ToDictionary(x => x.Key, x => (object)x.Value);
var result = Enumerable.Empty<PreValueFieldDisplay>().ToArray();
var result = Enumerable.Empty<PreValueFieldDisplay>();
//if we have a prop editor, then format the pre-values based on it and create it's fields.
if (propEd != null)
{
result = propEd.PreValueEditor.Fields.Select(Mapper.Map<PreValueFieldDisplay>).ToArray();
result = propEd.PreValueEditor.Fields.Select(Mapper.Map<PreValueFieldDisplay>).ToArray();
dictionaryVals = propEd.PreValueEditor.FormatDataForEditor(propEd.DefaultPreValues, preVals);
}
var currentIndex = 0; //used if the collection is non-dictionary based.
//now we need to wire up the pre-values values with the actual fields defined
foreach (var field in result)
{
if (preVals.IsDictionaryBased == false)
@@ -54,7 +59,7 @@ namespace Umbraco.Web.Models.Mapping
LogHelper.Warn<PreValueDisplayResolver>("Could not find persisted pre-value for index " + currentIndex);
continue;
}
field.Value = (string) dictionaryVals.Single(x => x.Key.InvariantEquals(currentIndex.ToInvariantString())).Value;
field.Value = dictionaryVals.Single(x => x.Key.InvariantEquals(currentIndex.ToInvariantString())).Value.ToString();
currentIndex++;
}
else
@@ -65,13 +70,18 @@ namespace Umbraco.Web.Models.Mapping
LogHelper.Warn<PreValueDisplayResolver>("Could not find persisted pre-value for field " + field.Key);
continue;
}
field.Value = (string)dictionaryVals.Single(x => x.Key.InvariantEquals(field.Key)).Value;
field.Value = dictionaryVals.Single(x => x.Key.InvariantEquals(field.Key)).Value.ToString();
}
}
return result;
}
protected override IEnumerable<PreValueFieldDisplay> ResolveCore(IDataTypeDefinition source)
{
return Convert(source);
}
}
}

View File

@@ -5,36 +5,9 @@ using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using umbraco;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.DropDownList, "Dropdown list", "dropdown")]
public class DropDownPropertyEditor : PropertyEditor
{
protected override PreValueEditor CreatePreValueEditor()
{
var editor = base.CreatePreValueEditor();
editor.Fields = new List<PreValueField>
{
new PreValueField
{
Description = "Add and remove values for the drop down list",
//we're going to call this 'temp' because we are going to override the
//serialization of the pre-values to ensure that each one gets saved with it's own key
//(new db row per pre-value, thus to maintain backwards compatibility)
Key = "temp",
Name = ui.Text("editdatatype", "addPrevalue"),
View = "Views/PropertyEditors/dropdown/dropdown.prevalue.html"
}
};
return editor;
}
}
[PropertyEditor(Constants.PropertyEditors.Date, "Date", "DATE", "datepicker")]
public class DatePropertyEditor : PropertyEditor
{
@@ -79,7 +52,7 @@ namespace Umbraco.Web.PropertyEditors
Validators = new List<ValidatorBase> { new DateTimeValidator() };
}
public override string SerializeValue(object dbValue)
public override string FormatDataForEditor(object dbValue)
{
var date = dbValue.TryConvertTo<DateTime?>();
if (date.Success == false || date.Result == null)

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
internal class DropDownPreValueEditor : PreValueEditor
{
/// <summary>
/// The editor is expecting a json array for a field with a key named "temp" so we need to format the persisted values
/// to this format to be used in the editor.
/// </summary>
/// <param name="defaultPreVals"></param>
/// <param name="persistedPreVals"></param>
/// <returns></returns>
public override IDictionary<string, object> FormatDataForEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
{
var dictionary = PreValueCollection.AsDictionary(persistedPreVals);
var arrayOfVals = dictionary.Select(item => item.Value).ToList();
var json = JsonConvert.SerializeObject(arrayOfVals);
return new Dictionary<string, object> {{"temp", json}};
}
/// <summary>
/// Need to format the delimited posted string to individual values
/// </summary>
/// <param name="editorValue"></param>
/// <param name="currentValue"></param>
/// <returns></returns>
/// <remarks>
/// This is mostly because we want to maintain compatibility with v6 drop down property editors that store their prevalues in different db rows.
/// </remarks>
public override IDictionary<string, string> FormatDataForPersistence(IDictionary<string, string> editorValue, Core.Models.PreValueCollection currentValue)
{
var val = editorValue["temp"];
var result = new Dictionary<string, string>();
if (val.IsNullOrWhiteSpace()) return result;
try
{
var deserialized = JsonConvert.DeserializeObject<string[]>(val);
var index = 0;
foreach (var item in deserialized)
{
result.Add(index.ToInvariantString(), item);
index++;
}
}
catch (Exception ex)
{
LogHelper.Error<DropDownPreValueEditor>("Could not deserialize the posted value: " + val, ex);
}
return result;
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
using umbraco;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.DropDownList, "Dropdown list", "dropdown")]
public class DropDownPropertyEditor : PropertyEditor
{
protected override PreValueEditor CreatePreValueEditor()
{
var editor = new DropDownPreValueEditor
{
Fields = new List<PreValueField>
{
new PreValueField
{
Description = "Add and remove values for the drop down list",
//we're going to call this 'temp' because we are going to override the
//serialization of the pre-values to ensure that each one gets saved with it's own key
//(new db row per pre-value, thus to maintain backwards compatibility)
Key = "temp",
Name = ui.Text("editdatatype", "addPrevalue"),
View = "Views/PropertyEditors/dropdown/dropdown.prevalue.html"
}
}
};
return editor;
}
}
}

View File

@@ -39,7 +39,7 @@ namespace Umbraco.Web.PropertyEditors
/// file path or use the existing file path.
/// </param>
/// <returns></returns>
public override object DeserializeValue(ContentPropertyData editorValue, object currentValue)
public override object FormatDataForPersistence(ContentPropertyData editorValue, object currentValue)
{
if (currentValue == null)
{

View File

@@ -317,6 +317,8 @@
<Compile Include="PropertyEditors\DatePropertyEditor.cs" />
<Compile Include="PropertyEditors\DateTimePropertyEditor.cs" />
<Compile Include="PropertyEditors\DateTimeValidator.cs" />
<Compile Include="PropertyEditors\DropDownPreValueEditor.cs" />
<Compile Include="PropertyEditors\DropDownPropertyEditor.cs" />
<Compile Include="PropertyEditors\LabelPropertyEditor.cs" />
<Compile Include="PropertyEditors\LabelValueEditor.cs" />
<Compile Include="Routing\UrlProviderExtensions.cs" />