diff --git a/src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs b/src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs
index 5ae30fd0ce..334341c2f6 100644
--- a/src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs
+++ b/src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs
@@ -8,9 +8,22 @@ namespace Umbraco.Core.PropertyEditors
[AttributeUsage(AttributeTargets.Class)]
public class SupportTagsAttribute : Attribute
{
- //TODO: We should be able to add an overload to this to provide a 'tag definition' so developers can dynamically change
- // things like TagGroup and ReplaceTags at runtime.
+ public Type TagPropertyDefinitionType { get; private set; }
+ ///
+ /// Defines a tag property definition type to invoke at runtime to get the tags configuration for a property
+ ///
+ ///
+ public SupportTagsAttribute(Type tagPropertyDefinitionType)
+ : this()
+ {
+ if (tagPropertyDefinitionType == null) throw new ArgumentNullException("tagPropertyDefinitionType");
+ TagPropertyDefinitionType = tagPropertyDefinitionType;
+ }
+
+ ///
+ /// Normal constructor specifying the default tags configuration for a property
+ ///
public SupportTagsAttribute()
{
ValueType = TagValueType.FromDelimitedValue;
diff --git a/src/Umbraco.Core/PropertyEditors/TagPropertyDefinition.cs b/src/Umbraco.Core/PropertyEditors/TagPropertyDefinition.cs
new file mode 100644
index 0000000000..a4a8d6dd30
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/TagPropertyDefinition.cs
@@ -0,0 +1,51 @@
+using Umbraco.Core.Models.Editors;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Allows for dynamically changing how a property's data is tagged at runtime during property setting
+ ///
+ public abstract class TagPropertyDefinition
+ {
+ ///
+ /// The property data that will create the tag data
+ ///
+ public ContentPropertyData PropertySaving { get; private set; }
+
+ ///
+ /// The attribute that has specified this definition type
+ ///
+ public SupportTagsAttribute TagsAttribute { get; set; }
+
+ ///
+ /// Constructor specifies the defaults and sets the ContentPropertyData being used to set the tag values which
+ /// can be used to dynamically adjust the tags definition for this property.
+ ///
+ ///
+ ///
+ protected TagPropertyDefinition(ContentPropertyData propertySaving, SupportTagsAttribute tagsAttribute)
+ {
+ PropertySaving = propertySaving;
+ TagsAttribute = tagsAttribute;
+ Delimiter = tagsAttribute.Delimiter;
+ ReplaceTags = tagsAttribute.ReplaceTags;
+ TagGroup = tagsAttribute.TagGroup;
+ }
+
+ ///
+ /// Defines a custom delimiter, the default is a comma
+ ///
+ public virtual string Delimiter { get; private set; }
+
+ ///
+ /// Determines whether or not to replace the tags with the new value or append them (true to replace, false to append), default is true
+ ///
+ public virtual bool ReplaceTags { get; private set; }
+
+ ///
+ /// The tag group to use when tagging, the default is 'default'
+ ///
+ public virtual string TagGroup { get; private set; }
+ }
+
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 0ded0c0d5e..e246fc1a4f 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -334,6 +334,7 @@
+
diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs
index aff3624015..4d8add3866 100644
--- a/src/Umbraco.Web/Editors/ContentControllerBase.cs
+++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs
@@ -116,8 +116,8 @@ namespace Umbraco.Web.Editors
var propVal = p.PropertyEditor.ValueEditor.ConvertEditorToDb(data, dboProperty.Value);
var supportTagsAttribute = TagExtractor.GetAttribute(p.PropertyEditor);
if (supportTagsAttribute != null)
- {
- TagExtractor.SetPropertyTags(contentItem.PersistedContent, dboProperty, propVal, supportTagsAttribute);
+ {
+ TagExtractor.SetPropertyTags(contentItem.PersistedContent, dboProperty, data, propVal, supportTagsAttribute);
}
else
{
diff --git a/src/Umbraco.Web/Editors/DataTypeController.cs b/src/Umbraco.Web/Editors/DataTypeController.cs
index 6919552540..bb6fcab711 100644
--- a/src/Umbraco.Web/Editors/DataTypeController.cs
+++ b/src/Umbraco.Web/Editors/DataTypeController.cs
@@ -10,6 +10,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
+using Umbraco.Web.Models.Mapping;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Binders;
using Umbraco.Web.WebApi.Filters;
@@ -42,10 +43,6 @@ namespace Umbraco.Web.Editors
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
-
- //TODO: Here we need to do a legacy check... if we cannot find a property editor with the alias
- // we should display a warning but let them select a different one!
-
return Mapper.Map(dataType);
}
@@ -62,8 +59,7 @@ namespace Umbraco.Web.Editors
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
-
-
+
Services.DataTypeService.Delete(foundType, UmbracoUser.Id);
return Request.CreateResponse(HttpStatusCode.OK);
@@ -91,8 +87,8 @@ namespace Umbraco.Web.Editors
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);
+ //this is a new data type, so just return the field editors with default values
+ return Mapper.Map>(propEd);
}
//we have a data type associated
@@ -111,8 +107,8 @@ namespace Umbraco.Web.Editors
return Mapper.Map>(dataType);
}
- //return the pre value display without values
- return propEd.PreValueEditor.Fields.Select(Mapper.Map);
+ //these are new pre-values, so just return the field editors with default values
+ return Mapper.Map>(propEd);
}
//TODO: Generally there probably won't be file uploads for pre-values but we should allow them just like we do for the content editor
diff --git a/src/Umbraco.Web/Editors/TagExtractor.cs b/src/Umbraco.Web/Editors/TagExtractor.cs
index ad2a8156d9..e8542ce588 100644
--- a/src/Umbraco.Web/Editors/TagExtractor.cs
+++ b/src/Umbraco.Web/Editors/TagExtractor.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using Umbraco.Core;
+using Umbraco.Core.Logging;
using Umbraco.Core.Models;
+using Umbraco.Core.Models.Editors;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.Editors
@@ -22,22 +24,47 @@ namespace Umbraco.Web.Editors
///
///
///
- ///
+ ///
+ ///
///
- public static void SetPropertyTags(IContentBase content, Property property, object propertyValue, SupportTagsAttribute attribute)
+ public static void SetPropertyTags(IContentBase content, Property property, ContentPropertyData propertyData, object convertedPropertyValue, SupportTagsAttribute attribute)
{
- switch (attribute.ValueType)
+ //check for a custom definition
+ if (attribute.TagPropertyDefinitionType != null)
+ {
+ //try to create it
+ TagPropertyDefinition def;
+ try
+ {
+ def = (TagPropertyDefinition) Activator.CreateInstance(attribute.TagPropertyDefinitionType, propertyData, attribute);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.Error("Could not create custom " + attribute.TagPropertyDefinitionType + " tag definition", ex);
+ throw;
+ }
+ SetPropertyTags(content, property, convertedPropertyValue, def.Delimiter, def.ReplaceTags, def.TagGroup, attribute.ValueType);
+ }
+ else
+ {
+ SetPropertyTags(content, property, convertedPropertyValue, attribute.Delimiter, attribute.ReplaceTags, attribute.TagGroup, attribute.ValueType);
+ }
+ }
+
+ public static void SetPropertyTags(IContentBase content, Property property, object convertedPropertyValue, string delimiter, bool replaceTags, string tagGroup, TagValueType valueType)
+ {
+ switch (valueType)
{
case TagValueType.FromDelimitedValue:
- var tags = propertyValue.ToString().Split(new[] { attribute.Delimiter }, StringSplitOptions.RemoveEmptyEntries);
- content.SetTags(property.Alias, tags, attribute.ReplaceTags, attribute.TagGroup);
+ var tags = convertedPropertyValue.ToString().Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries);
+ content.SetTags(property.Alias, tags, replaceTags, tagGroup);
break;
case TagValueType.CustomTagList:
//for this to work the object value must be IENumerable
- var stringList = propertyValue as IEnumerable;
+ var stringList = convertedPropertyValue as IEnumerable;
if (stringList != null)
{
- content.SetTags(property.Alias, stringList, attribute.ReplaceTags, attribute.TagGroup);
+ content.SetTags(property.Alias, stringList, replaceTags, tagGroup);
}
break;
}
diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs
index 3b0e941605..77c8201f75 100644
--- a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs
@@ -39,8 +39,7 @@ namespace Umbraco.Web.Models.Mapping
{
var resolver = new PreValueDisplayResolver(lazyDataTypeService);
return resolver.Convert(definition);
- });
-
+ });
config.CreateMap()
.ConstructUsing(save => new DataTypeDefinition(-1, save.SelectedEditor) {CreateDate = DateTime.Now})
@@ -48,6 +47,20 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(definition => definition.PropertyEditorAlias, expression => expression.MapFrom(save => save.SelectedEditor))
.ForMember(definition => definition.ParentId, expression => expression.MapFrom(save => -1))
.ForMember(definition => definition.DatabaseType, expression => expression.ResolveUsing());
+
+ //Converts a property editor to a new list of pre-value fields - used when creating a new data type or changing a data type with new pre-vals
+ config.CreateMap>()
+ .ConvertUsing(editor =>
+ {
+ //this is a new data type, so just return the field editors, there are no values yet
+ var defaultVals = editor.DefaultPreValues;
+ var fields = editor.PreValueEditor.Fields.Select(Mapper.Map).ToArray();
+ if (defaultVals != null)
+ {
+ PreValueDisplayResolver.MapPreValueValuesToPreValueFields(fields, defaultVals, true);
+ }
+ return fields;
+ });
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs b/src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs
index 8af766ae5c..a7bf89a1d2 100644
--- a/src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs
@@ -20,6 +20,47 @@ namespace Umbraco.Web.Models.Mapping
_dataTypeService = dataTypeService;
}
+ ///
+ /// Maps pre-values in the dictionary to the values for the fields
+ ///
+ ///
+ ///
+ ///
+ internal static void MapPreValueValuesToPreValueFields(PreValueFieldDisplay[] fields, IDictionary preValues, bool isDictionaryBased)
+ {
+ if (fields == null) throw new ArgumentNullException("fields");
+ if (preValues == null) throw new ArgumentNullException("preValues");
+ //now we need to wire up the pre-values values with the actual fields defined
+ var currentIndex = 0; //used if the collection is non-dictionary based.
+ foreach (var field in fields)
+ {
+ if (isDictionaryBased == false)
+ {
+ //we'll just need to wire up the values based on the order that the pre-values are stored
+ var found = preValues.Any(x => x.Key.InvariantEquals(currentIndex.ToInvariantString()));
+ if (found == false)
+ {
+ LogHelper.Warn("Could not find persisted pre-value for index " + currentIndex);
+ continue;
+ }
+ field.Value = preValues.Single(x => x.Key.InvariantEquals(currentIndex.ToInvariantString())).Value.ToString();
+ currentIndex++;
+ }
+ else
+ {
+ var found = preValues.Any(x => x.Key.InvariantEquals(field.Key));
+ if (found == false)
+ {
+ LogHelper.Warn("Could not find persisted pre-value for field " + field.Key);
+ continue;
+ }
+ field.Value = preValues.Single(x => x.Key.InvariantEquals(field.Key)).Value;
+ }
+
+
+ }
+ }
+
internal IEnumerable Convert(IDataTypeDefinition source)
{
PropertyEditor propEd = null;
@@ -45,36 +86,7 @@ namespace Umbraco.Web.Models.Mapping
dictionaryVals = propEd.PreValueEditor.ConvertDbToEditor(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)
- {
- //we'll just need to wire up the values based on the order that the pre-values are stored
- var found = dictionaryVals.Any(x => x.Key.InvariantEquals(currentIndex.ToInvariantString()));
- if (found == false)
- {
- LogHelper.Warn("Could not find persisted pre-value for index " + currentIndex);
- continue;
- }
- field.Value = dictionaryVals.Single(x => x.Key.InvariantEquals(currentIndex.ToInvariantString())).Value.ToString();
- currentIndex++;
- }
- else
- {
- var found = dictionaryVals.Any(x => x.Key.InvariantEquals(field.Key));
- if (found == false)
- {
- LogHelper.Warn("Could not find persisted pre-value for field " + field.Key);
- continue;
- }
- field.Value = dictionaryVals.Single(x => x.Key.InvariantEquals(field.Key)).Value;
- }
-
-
- }
+ MapPreValueValuesToPreValueFields(result, dictionaryVals, preVals.IsDictionaryBased);
return result;
}
diff --git a/src/Umbraco.Web/PropertyEditors/TagPropertyEditorTagDefinition.cs b/src/Umbraco.Web/PropertyEditors/TagPropertyEditorTagDefinition.cs
new file mode 100644
index 0000000000..31ceeb3d60
--- /dev/null
+++ b/src/Umbraco.Web/PropertyEditors/TagPropertyEditorTagDefinition.cs
@@ -0,0 +1,25 @@
+using Umbraco.Core.Models.Editors;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Web.PropertyEditors
+{
+ ///
+ /// Used to dynamically change the tag group based on the pre-values
+ ///
+ internal class TagPropertyEditorTagDefinition : TagPropertyDefinition
+ {
+ public TagPropertyEditorTagDefinition(ContentPropertyData propertySaving, SupportTagsAttribute tagsAttribute)
+ : base(propertySaving, tagsAttribute)
+ {
+ }
+
+ public override string TagGroup
+ {
+ get
+ {
+ var preVals = PropertySaving.PreValues.FormatAsDictionary();
+ return preVals.ContainsKey("group") ? preVals["group"].Value : "default";
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs
index 35b6afb8cc..59115ad263 100644
--- a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs
@@ -1,11 +1,55 @@
-using Umbraco.Core;
+using System.Collections.Generic;
+using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
- [SupportTags]
+ [SupportTags(typeof(TagPropertyEditorTagDefinition))]
[PropertyEditor(Constants.PropertyEditors.TagsAlias, "Tags", "tags")]
public class TagsPropertyEditor : PropertyEditor
{
+ public TagsPropertyEditor()
+ {
+ _defaultPreVals = new Dictionary
+ {
+ {"group", "default"}
+ };
+ }
+
+ private IDictionary _defaultPreVals;
+
+ ///
+ /// Override to supply the default group
+ ///
+ public override IDictionary DefaultPreValues
+ {
+ get { return _defaultPreVals; }
+ set { _defaultPreVals = value; }
+ }
+
+ protected override PreValueEditor CreatePreValueEditor()
+ {
+ return new TagPreValueEditor();
+ }
+
+ internal class TagPreValueEditor : PreValueEditor
+ {
+ public TagPreValueEditor()
+ {
+ Fields.Add(new PreValueField(new ManifestPropertyValidator { Type = "Required" })
+ {
+ Description = "Define a tag group",
+ Key = "group",
+ Name = "Tag group",
+ View = "requiredfield"
+ });
+ }
+
+ public override IDictionary ConvertDbToEditor(IDictionary defaultPreVals, Core.Models.PreValueCollection persistedPreVals)
+ {
+ var result = base.ConvertDbToEditor(defaultPreVals, persistedPreVals);
+ return result;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index a4910ac271..44606d2f0d 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -384,6 +384,7 @@
+