diff --git a/Gruntfile.js b/Gruntfile.js index a26446f..b5ae969 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -89,12 +89,6 @@ module.exports = function(grunt) { dest: '<%= basePath %>', expand: true }, - { - cwd: 'app/config/', - src: ['propertyEditors.views.js'], - dest: '<%= basePath %>/js', - expand: true - }, { cwd: 'app/langs/', src: ['**'], diff --git a/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj b/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj index df29425..e790eb8 100644 --- a/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj +++ b/app/Umbraco/Archetype.Tests/Archetype.Tests.csproj @@ -31,21 +31,171 @@ 4 + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\businesslogic.dll + + + ..\packages\ClientDependency.1.7.1.2\lib\ClientDependency.Core.dll + + + ..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\cms.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\controls.dll + + + ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\Examine.dll + + + ..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + + + ..\packages\ImageProcessor.1.8.7.0\lib\ImageProcessor.dll + + + ..\packages\ImageProcessor.Web.3.2.1.0\lib\net45\ImageProcessor.Web.dll + + + False + ..\packages\UmbracoCms.Core.7.1.0\lib\interfaces.dll + + + False + ..\packages\UmbracoCms.Core.7.1.0\lib\log4net.dll + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\Microsoft.ApplicationBlocks.Data.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\Microsoft.Web.Helpers.dll + + + True + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + ..\packages\Moq.4.2.1312.1622\lib\net40\Moq.dll + + ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll + + + ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + ..\packages\UmbracoCms.Core.7.1.0\lib\SQLCE4Umbraco.dll + + + True + ..\packages\UmbracoCms.Core.7.1.0\lib\System.Data.SqlServerCe.dll + + + True + ..\packages\UmbracoCms.Core.7.1.0\lib\System.Data.SqlServerCe.Entity.dll + + + + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll + + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll + + + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll + + + True + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll + + + False + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll + True + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll + - - ..\packages\UmbracoCms.Core.7.0.1\lib\Umbraco.Core.dll + + ..\packages\UmbracoCms.Core.7.1.0\lib\TidyNet.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.dll + + + False + ..\packages\UmbracoCms.Core.7.1.0\lib\Umbraco.Core.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.DataLayer.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.editorControls.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.MacroEngines.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.providers.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\Umbraco.Web.UI.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.XmlSerializers.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\UmbracoExamine.dll + + + ..\packages\UmbracoCms.Core.7.1.0\lib\UrlRewritingNet.UrlRewriter.dll @@ -54,6 +204,7 @@ + diff --git a/app/Umbraco/Archetype.Tests/PropertyValueConverter/PropertyValueConverterTests.cs b/app/Umbraco/Archetype.Tests/PropertyValueConverter/PropertyValueConverterTests.cs index 710be06..6329a4d 100644 --- a/app/Umbraco/Archetype.Tests/PropertyValueConverter/PropertyValueConverterTests.cs +++ b/app/Umbraco/Archetype.Tests/PropertyValueConverter/PropertyValueConverterTests.cs @@ -24,32 +24,30 @@ namespace Archetype.Tests.PropertyValueConverter } [Test] - public void Returns_Null_When_Data_Is_Null() + [TestCase(null)] + [TestCase("")] + public void Returns_Empty_Archetype_When_Data_Is_Null_Or_Empty(object data) { - var converter = new ArchetypeValueConverter(); - var result = converter.ConvertDataToSource(null, null, false); - - Assert.IsNull(result); - } - - [Test] - public void Returns_Empty_String_When_Data_Is_Empty_String() - { - var data = ""; var converter = new ArchetypeValueConverter(); var result = converter.ConvertDataToSource(null, data, false); - Assert.AreEqual("", result); + Assert.AreEqual(result.GetType(), typeof (Archetype.Umbraco.Models.Archetype)); + + var fieldsets = (Archetype.Umbraco.Models.Archetype) result; + Assert.IsTrue(fieldsets.Count() == 0); } [Test] - public void Returns_Original_String_When_Data_Is_Invalid_Json() + public void Returns_Empty_Archetype_When_Data_Is_Invalid_Json() { var data = "{ invalid"; var converter = new ArchetypeValueConverter(); var result = converter.ConvertDataToSource(null, data, false); - Assert.AreEqual(data, result); + Assert.AreEqual(result.GetType(), typeof (Archetype.Umbraco.Models.Archetype)); + + var fieldsets = (Archetype.Umbraco.Models.Archetype) result; + Assert.IsTrue(fieldsets.Count() == 0); } [Test] diff --git a/app/Umbraco/Archetype.Tests/app.config b/app/Umbraco/Archetype.Tests/app.config new file mode 100644 index 0000000..e509377 --- /dev/null +++ b/app/Umbraco/Archetype.Tests/app.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/Umbraco/Archetype.Tests/packages.config b/app/Umbraco/Archetype.Tests/packages.config index c90677c..66fbf23 100644 --- a/app/Umbraco/Archetype.Tests/packages.config +++ b/app/Umbraco/Archetype.Tests/packages.config @@ -1,5 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/Umbraco/Umbraco.Archetype/Api/ArchetypeDataTypeController.cs b/app/Umbraco/Umbraco.Archetype/Api/ArchetypeDataTypeController.cs index 6bdb7ce..3a03b2f 100644 --- a/app/Umbraco/Umbraco.Archetype/Api/ArchetypeDataTypeController.cs +++ b/app/Umbraco/Umbraco.Archetype/Api/ArchetypeDataTypeController.cs @@ -1,4 +1,7 @@ -using System.Net; +using System.Collections.Generic; +using System; +using System.Linq; +using System.Net; using System.Web.Http; using AutoMapper; using Umbraco.Core.Models; @@ -11,9 +14,23 @@ namespace Archetype.Umbraco.Api [PluginController("ArchetypeApi")] public class ArchetypeDataTypeController : UmbracoAuthorizedJsonController { - public object GetById(int id) + + public IEnumerable GetAllPropertyEditors() { - var dataType = Services.DataTypeService.GetDataTypeDefinitionById(id); + return + global::Umbraco.Core.PropertyEditors.PropertyEditorResolver.Current.PropertyEditors + .Select(x => new {defaultPreValues = x.DefaultPreValues, alias = x.Alias, view = x.ValueEditor.View}); + } + + public object GetAll() + { + var dataTypes = Services.DataTypeService.GetAllDataTypeDefinitions(); + return dataTypes.Select(t => new { guid = t.Key, name = t.Name }); + } + + public object GetByGuid(Guid guid) + { + var dataType = Services.DataTypeService.GetDataTypeDefinitionById(guid); if (dataType == null) { throw new HttpResponseException(HttpStatusCode.NotFound); diff --git a/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj b/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj index 05ed8ed..6fa2f8a 100644 --- a/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj +++ b/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj @@ -41,32 +41,27 @@ False - ..\packages\UmbracoCms.Core.7.0.1\lib\businesslogic.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\businesslogic.dll - ..\packages\ClientDependency.1.7.0.4\lib\ClientDependency.Core.dll - False + ..\packages\ClientDependency.1.7.1.2\lib\ClientDependency.Core.dll ..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll False - ..\packages\UmbracoCms.Core.7.0.1\lib\cms.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\cms.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\controls.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\controls.dll ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll False - ..\packages\UmbracoCms.Core.7.0.1\lib\Examine.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\Examine.dll ..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll @@ -76,25 +71,27 @@ ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll False + + ..\packages\ImageProcessor.1.8.7.0\lib\ImageProcessor.dll + + + ..\packages\ImageProcessor.Web.3.2.1.0\lib\net45\ImageProcessor.Web.dll + - ..\packages\UmbracoCms.Core.7.0.1\lib\interfaces.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\interfaces.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\log4net.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\log4net.dll ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll False - ..\packages\UmbracoCms.Core.7.0.1\lib\Microsoft.ApplicationBlocks.Data.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\Microsoft.ApplicationBlocks.Data.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\Microsoft.Web.Helpers.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\Microsoft.Web.Helpers.dll False @@ -117,18 +114,17 @@ False - ..\packages\UmbracoCms.Core.7.0.1\lib\SQLCE4Umbraco.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\SQLCE4Umbraco.dll - False - ..\packages\UmbracoCms.Core.7.0.1\lib\System.Data.SqlServerCe.dll + True + ..\packages\UmbracoCms.Core.7.1.0\lib\System.Data.SqlServerCe.dll - False - ..\packages\UmbracoCms.Core.7.0.1\lib\System.Data.SqlServerCe.Entity.dll + True + ..\packages\UmbracoCms.Core.7.1.0\lib\System.Data.SqlServerCe.Entity.dll @@ -136,6 +132,7 @@ False + False ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll @@ -174,48 +171,37 @@ - ..\packages\UmbracoCms.Core.7.0.1\lib\TidyNet.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\TidyNet.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\Umbraco.Core.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\Umbraco.Core.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.DataLayer.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.DataLayer.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.editorControls.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.editorControls.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.MacroEngines.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.MacroEngines.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.providers.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.providers.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\Umbraco.Web.UI.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\Umbraco.Web.UI.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.XmlSerializers.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\umbraco.XmlSerializers.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\UmbracoExamine.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\UmbracoExamine.dll - ..\packages\UmbracoCms.Core.7.0.1\lib\UrlRewritingNet.UrlRewriter.dll - False + ..\packages\UmbracoCms.Core.7.1.0\lib\UrlRewritingNet.UrlRewriter.dll diff --git a/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValue.cs b/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValue.cs index 1a7e4a2..653af0e 100644 --- a/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValue.cs +++ b/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValue.cs @@ -6,7 +6,10 @@ namespace Archetype.Umbraco.Models public class ArchetypePreValue { [JsonProperty("showAdvancedOptions")] - public bool ShowAdvancedOptions { get; set; } + public bool ShowAdvancedOptions { get; set; } + + [JsonProperty("startWithAddButton")] + public bool StartWithAddButton { get; set; } [JsonProperty("hideFieldsetToolbar")] public bool HideFieldsetToolbar { get; set; } diff --git a/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValueProperty.cs b/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValueProperty.cs index c8c13e4..e2cc12b 100644 --- a/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValueProperty.cs +++ b/app/Umbraco/Umbraco.Archetype/Models/ArchetypePreValueProperty.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; namespace Archetype.Umbraco.Models { @@ -18,12 +19,9 @@ namespace Archetype.Umbraco.Models [JsonProperty("helpText")] public string HelpText { get; set; } - - [JsonProperty("dataTypeId")] - public int DataTypeId { get; set; } - + [JsonProperty("dataTypeGuid")] - public string DataTypeGuid { get; set; } + public Guid DataTypeGuid { get; set; } [JsonProperty("propertyEditorAlias")] public string PropertyEditorAlias { get; set; } diff --git a/app/Umbraco/Umbraco.Archetype/Models/Property.cs b/app/Umbraco/Umbraco.Archetype/Models/Property.cs index 09605b7..a3c4522 100644 --- a/app/Umbraco/Umbraco.Archetype/Models/Property.cs +++ b/app/Umbraco/Umbraco.Archetype/Models/Property.cs @@ -1,9 +1,11 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Web; namespace Archetype.Umbraco.Models { @@ -30,14 +32,26 @@ namespace Archetype.Umbraco.Models if (Value is T) return (T)Value; - // Umbraco has the concept of a IPropertyEditorValueConverter which it - // also queries for property resolvers. However I'm not sure what these - // are for, nor can I find any implementations in core, so am currently - // just ignoring these when looking up converters. - // NB: IPropertyEditorValueConverter not to be confused with - // IPropertyValueConverter which are the ones most people are creating + // Try Umbraco's PropertyValueConverters + var converters = UmbracoContext.Current != null ? PropertyValueConvertersResolver.Current.Converters : Enumerable.Empty(); + if (converters.Any()) + { + var convertedAttempt = TryConvertWithPropertyValueConverters(Value, converters); + if (convertedAttempt.Success) + return convertedAttempt.Result; + } + + // No PropertyValueConverters matched, so try a regular type conversion + var convertAttempt2 = Value.TryConvertTo(); + if (convertAttempt2.Success) + return convertAttempt2.Result; + + return default(T); + } + + private Attempt TryConvertWithPropertyValueConverters(object value, IEnumerable converters) + { var properyType = CreateDummyPropertyType(DataTypeId, PropertyEditorAlias); - var converters = PropertyValueConvertersResolver.Current.Converters.ToArray(); // In umbraco, there are default value converters that try to convert the // value if all else fails. The problem is, they are also in the list of @@ -49,24 +63,19 @@ namespace Archetype.Umbraco.Models foreach (var converter in converters.Where(x => x.IsConverter(properyType))) { // Convert the type using a found value converter - var value2 = converter.ConvertDataToSource(properyType, Value, false); + var value2 = converter.ConvertDataToSource(properyType, value, false); // If the value is of type T, just return it if (value2 is T) - return (T)value2; + return Attempt.Succeed((T)value2); // Value is not final value type, so try a regular type conversion aswell var convertAttempt = value2.TryConvertTo(); if (convertAttempt.Success) - return convertAttempt.Result; + return Attempt.Succeed(convertAttempt.Result); } - // Value is not final value type, so try a regular type conversion - var convertAttempt2 = Value.TryConvertTo(); - if (convertAttempt2.Success) - return convertAttempt2.Result; - - return default(T); + return Attempt.Fail(); } private PublishedPropertyType CreateDummyPropertyType(int dataTypeId, string propertyEditorAlias) diff --git a/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs b/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs index a8bfc8b..95a0411 100644 --- a/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs +++ b/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs @@ -1,13 +1,15 @@ -using System; +using System; +using System.Collections.Generic; using System.Linq; using Archetype.Umbraco.Extensions; using Archetype.Umbraco.Models; using Newtonsoft.Json; -using Umbraco.Core; +using Umbraco.Core; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Services; - +using Umbraco.Core.Services; + namespace Archetype.Umbraco.PropertyConverters { /* based on the Tim Geyssens sample at: https://github.com/TimGeyssens/MatrixPropEditor/blob/master/SamplePropertyValueConverter/SamplePropertyValueConverter/MatrixValueConverter.cs */ @@ -54,8 +56,9 @@ namespace Archetype.Umbraco.PropertyConverters try { // Get list of configured properties and their types - // and map them to the deserialized archetype model - var preValue = GetArchetypePreValueFromDataTypeId(propertyType.DataTypeId); + // and map them to the deserialized archetype model + var dataTypeCache = new Dictionary(); + var preValue = GetArchetypePreValueFromDataTypeId(propertyType.DataTypeId, dataTypeCache); foreach (var fieldset in preValue.Fieldsets) { var fieldsetAlias = fieldset.Alias; @@ -64,9 +67,9 @@ namespace Archetype.Umbraco.PropertyConverters foreach (var property in fieldset.Properties) { var propertyAlias = property.Alias; - foreach (var propertyInst in fieldsetInst.Properties.Where(x => x.Alias == propertyAlias)) - { - propertyInst.DataTypeId = property.DataTypeId; + foreach (var propertyInst in fieldsetInst.Properties.Where(x => x.Alias == propertyAlias)) + { + propertyInst.DataTypeId = GetDataTypeByGuid(property.DataTypeGuid, dataTypeCache).Id; propertyInst.PropertyEditorAlias = property.PropertyEditorAlias; } } @@ -86,9 +89,9 @@ namespace Archetype.Umbraco.PropertyConverters } return defaultValue; - } - - internal ArchetypePreValue GetArchetypePreValueFromDataTypeId(int dataTypeId) + } + + private ArchetypePreValue GetArchetypePreValueFromDataTypeId(int dataTypeId, IDictionary dataTypeCache) { var preValues = Services.DataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeId); @@ -102,18 +105,22 @@ namespace Archetype.Umbraco.PropertyConverters { foreach (var property in fieldset.Properties) { - // Lookup the properties property editor alias - // (See if we've already looked it up first though to save a database hit) - var propertyWithSameDataType = config.Fieldsets.SelectMany(x => x.Properties) - .FirstOrDefault(x => x.DataTypeId == property.DataTypeId && !string.IsNullOrWhiteSpace(x.PropertyEditorAlias)); - - property.PropertyEditorAlias = propertyWithSameDataType != null - ? propertyWithSameDataType.PropertyEditorAlias - : Services.DataTypeService.GetDataTypeDefinitionById(property.DataTypeId).PropertyEditorAlias; + property.PropertyEditorAlias = GetDataTypeByGuid(property.DataTypeGuid, dataTypeCache).PropertyEditorAlias; } } return config; + } + + private IDataTypeDefinition GetDataTypeByGuid(Guid guid, IDictionary cache) + { + IDataTypeDefinition dataType; + if (cache.TryGetValue(guid, out dataType)) + return dataType; + + dataType = Services.DataTypeService.GetDataTypeDefinitionById(guid); + cache[guid] = dataType; + return dataType; } } } diff --git a/app/Umbraco/Umbraco.Archetype/packages.config b/app/Umbraco/Umbraco.Archetype/packages.config index 7918cdf..85afbc7 100644 --- a/app/Umbraco/Umbraco.Archetype/packages.config +++ b/app/Umbraco/Umbraco.Archetype/packages.config @@ -1,9 +1,11 @@ - + + + @@ -19,6 +21,6 @@ - + \ No newline at end of file diff --git a/app/config/propertyEditors.views.js b/app/config/propertyEditors.views.js deleted file mode 100644 index ba99e59..0000000 --- a/app/config/propertyEditors.views.js +++ /dev/null @@ -1,148 +0,0 @@ -[ - { - "propertyEditorAlias": "Umbraco.CheckBoxList", - "view": "checkboxlist" - }, - { - "propertyEditorAlias": "Umbraco.ColorPickerAlias", - "view": "colorpicker" - }, - { - "propertyEditorAlias": "Umbraco.ContentPickerAlias", - "view": "contentpicker" - }, - { - "propertyEditorAlias": "Umbraco.Date", - "view": "datepicker", - "defaultPreValues": [{ "format": "yyyy-MM-dd", "pickTime": false }] - }, - { - "propertyEditorAlias": "Umbraco.DateTime", - "view": "datepicker", - "format": "yyyy-MM-dd hh:mm:ss" - }, - { - "propertyEditorAlias": "Umbraco.DropDown", - "view": "dropdown" - }, - { - "propertyEditorAlias": "Umbraco.DropDownMultiple", - "view": "dropdown" - }, - { - "propertyEditorAlias": "Umbraco.DropDownMultiplePublishKeys", - "view": "dropdown" - }, - { - "propertyEditorAlias": "Umbraco.DropdownlistPublishingKeys", - "view": "dropdown" - }, - { - "propertyEditorAlias": "Umbraco.EmailAddress", - "view": "email" - }, - { - "propertyEditorAlias": "Umbraco.UploadField", - "view": "fileupload" - }, - { - "propertyEditorAlias": "Umbraco.FolderBrowser", - "view": "folderbrowser" - }, - { - "propertyEditorAlias": "Umbraco.Integer", - "view": "integer" - }, - { - "propertyEditorAlias": "Umbraco.NoEdit", - "view": "readonlyvalue" - }, - { - "propertyEditorAlias": "Umbraco.ListView", - "view": "listview" - }, - { - "propertyEditorAlias": "Umbraco.MacroContainer", - "view": "macrocontainer" - }, - { - "propertyEditorAlias": "Umbraco.MarkdownEditor", - "view": "markdowneditor" - }, - { - "propertyEditorAlias": "Umbraco.MediaPicker", - "view": "mediapicker", - "defaultPreValues": [{ "multiPicker": "0" }] - }, - { - "propertyEditorAlias": "Umbraco.MemberGroupPicker", - "view": "membergrouppicker" - }, - { - "propertyEditorAlias": "Umbraco.MemberPicker", - "view": "memberpicker" - }, - { - "propertyEditorAlias": "Umbraco.MultiNodeTreePicker", - "view": "contentpicker", - "defaultPreValues": [{ "multiPicker": "1" }] - }, - { - "propertyEditorAlias": "Umbraco.MultipleMediaPicker", - "view": "mediapicker" - }, - { - "propertyEditorAlias": "Umbraco.MultipleTextstring", - "view": "multipletextbox" - }, - { - "propertyEditorAlias": "Umbraco.RadioButtonList", - "view": "radiobuttons" - }, - { - "propertyEditorAlias": "Umbraco.RelatedLinks", - "view": "relatedlinks" - }, - { - "propertyEditorAlias": "Umbraco.TinyMCEv3", - "view": "rte" - }, - { - "propertyEditorAlias": "Umbraco.Slider", - "view": "slider" - }, - { - "propertyEditorAlias": "Umbraco.Tags", - "view": "tags", - "defaultPreValues": [{ "group": "default" }] - }, - { - "propertyEditorAlias": "Umbraco.TextboxMultiple", - "view": "textarea" - }, - { - "propertyEditorAlias": "Umbraco.Textbox", - "view": "textbox" - }, - { - "propertyEditorAlias": "Umbraco.TrueFalse", - "view": "boolean" - }, - { - "propertyEditorAlias": "Umbraco.UserPicker", - "view": "entitypicker", - "defaultPreValues": [{ "entityType": "User" }] - }, - { - "propertyEditorAlias": "Umbraco.NoEdit", - "view": "readonlyvalue" - }, - { - "propertyEditorAlias": "Umbraco.Textbox", - "view": "textbox" - }, - { - "propertyEditorAlias": "Imulus.Archetype", - "view": "/App_Plugins/Archetype/views/archetype.html" - } -] \ No newline at end of file diff --git a/app/controllers/config.controller.js b/app/controllers/config.controller.js index 0a3828f..6dd8ef5 100644 --- a/app/controllers/config.controller.js +++ b/app/controllers/config.controller.js @@ -1,19 +1,19 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", function ($scope, $http, assetsService, dialogService, archetypePropertyEditorResource) { - - //$scope.model.value = ""; - //console.log($scope.model.value); + + //$scope.model.value = ""; + //console.log($scope.model.value); //define empty items - var newPropertyModel = '{"alias": "", "remove": false, "collapse": false, "label": "", "helpText": "", "dataTypeId": "-88", "value": ""}'; + var newPropertyModel = '{"alias": "", "remove": false, "collapse": false, "label": "", "helpText": "", "dataTypeGuid": "0cc0eba1-9960-42c9-bf9b-60e150b429ae", "value": ""}'; var newFieldsetModel = '{"alias": "", "remove": false, "collapse": false, "labelTemplate": "", "icon": "", "label": "", "properties": [' + newPropertyModel + ']}'; - var defaultFieldsetConfigModel = JSON.parse('{"showAdvancedOptions": false, "hideFieldsetToolbar": false, "enableMultipleFieldsets": false, "hideFieldsetControls": false, "hidePropertyLabel": false, "maxFieldsets": null, "enableCollapsing": true, "fieldsets": [' + newFieldsetModel + ']}'); + var defaultFieldsetConfigModel = JSON.parse('{"showAdvancedOptions": false, "startWithAddButton": false, "hideFieldsetToolbar": false, "enableMultipleFieldsets": false, "hideFieldsetControls": false, "hidePropertyLabel": false, "maxFieldsets": null, "enableCollapsing": true, "fieldsets": [' + newFieldsetModel + ']}'); //ini the model $scope.model.value = $scope.model.value || defaultFieldsetConfigModel; - + //ini the render model initConfigRenderModel(); - + //get the available datatypes archetypePropertyEditorResource.getAllDataTypes().then(function(data) { $scope.availableDataTypes = data; @@ -40,16 +40,16 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio } }; - + //function that determines how to manage expanding/collapsing fieldsets $scope.focusFieldset = function(fieldset){ var iniState; - + if(fieldset) { iniState = fieldset.collapse; } - + _.each($scope.archetypeConfigRenderModel.fieldsets, function(fieldset){ if($scope.archetypeConfigRenderModel.fieldsets.length == 1 && fieldset.remove == false) { @@ -66,7 +66,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio fieldset.collapse = false; } }); - + if(iniState) { fieldset.collapse = !iniState; @@ -79,7 +79,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio //function that determines how to manage expanding/collapsing properties $scope.focusProperty = function(properties, property){ var iniState; - + if(property) { iniState = property.collapse; @@ -95,7 +95,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio property.collapse = false; } }); - + if(iniState) { property.collapse = !iniState; @@ -106,24 +106,24 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio _.each($scope.archetypeConfigRenderModel.fieldsets, function(fieldset){ $scope.focusProperty(fieldset.properties); }); - + //setup JSON.stringify helpers $scope.archetypeConfigRenderModel.toString = stringify; - + //encapsulate stringify (should be built into browsers, not sure of IE support) function stringify() { return JSON.stringify(this); } - + //watch for changes $scope.$watch('archetypeConfigRenderModel', function (v) { //console.log(v); - if (typeof v === 'string') { + if (typeof v === 'string') { $scope.archetypeConfigRenderModel = JSON.parse(v); $scope.archetypeConfigRenderModel.toString = stringify; } }); - + $scope.autoPopulateAlias = function(s) { var modelType = s.hasOwnProperty('fieldset') ? 'fieldset' : 'property'; var modelProperty = s[modelType]; @@ -144,7 +144,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio //helper that returns if an item can be removed $scope.canRemoveFieldset = function () - { + { return countVisibleFieldset() > 1; } @@ -153,10 +153,10 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio { return countVisibleFieldset() > 1; } - + //helper that returns if an item can be removed $scope.canRemoveProperty = function (fieldset) - { + { return countVisibleProperty(fieldset) > 1; } @@ -166,17 +166,17 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio return countVisibleProperty(fieldset) > 1; } - $scope.getDataTypeNameById = function (id) { + $scope.getDataTypeNameByGuid = function (guid) { if ($scope.availableDataTypes == null) // Might not be initialized yet? return ""; - + var dataType = _.find($scope.availableDataTypes, function(d) { - return d.id == id; + return d.guid == guid; }); return dataType == null ? "" : dataType.name; } - + //helper to count what is visible function countVisibleFieldset() { @@ -190,7 +190,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio return count; } - + //determines how many properties are visible function countVisibleProperty(fieldset) { @@ -204,13 +204,13 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio return count; } - + //handles a fieldset add $scope.addFieldsetRow = function ($index, $event) { $scope.archetypeConfigRenderModel.fieldsets.splice($index + 1, 0, JSON.parse(newFieldsetModel)); $scope.focusFieldset(); } - + //rather than splice the archetypeConfigRenderModel, we're hiding this and cleaning onFormSubmitting $scope.removeFieldsetRow = function ($index) { if ($scope.canRemoveFieldset()) { @@ -219,12 +219,12 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio } } } - + //handles a property add $scope.addPropertyRow = function (fieldset, $index) { fieldset.properties.splice($index + 1, 0, JSON.parse(newPropertyModel)); } - + //rather than splice the archetypeConfigRenderModel, we're hiding this and cleaning onFormSubmitting $scope.removePropertyRow = function (fieldset, $index) { if ($scope.canRemoveProperty(fieldset)) { @@ -233,7 +233,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio } } } - + //helper to ini the render model function initConfigRenderModel() { @@ -257,38 +257,38 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio }); }); } - + //sync things up on save $scope.$on("formSubmitting", function (ev, args) { syncModelToRenderModel(); }); - + //helper to sync the model to the renderModel function syncModelToRenderModel() { $scope.model.value = $scope.archetypeConfigRenderModel; var fieldsets = []; - + _.each($scope.archetypeConfigRenderModel.fieldsets, function(fieldset){ //check fieldsets if (!fieldset.remove) { fieldsets.push(fieldset); - + var properties = []; _.each(fieldset.properties, function(property){ if (!property.remove) { properties.push(property); - } + } }); fieldset.properties = properties; } }); - + $scope.model.value.fieldsets = fieldsets; } - + //archetype css assetsService.loadCss("/App_Plugins/Archetype/css/archetype.css"); }); diff --git a/app/controllers/controller.js b/app/controllers/controller.js index f89e0a9..9ceb769 100644 --- a/app/controllers/controller.js +++ b/app/controllers/controller.js @@ -1,5 +1,5 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($scope, $http, assetsService, angularHelper, notificationsService, $timeout) { - + //$scope.model.value = ""; $scope.model.hideLabel = $scope.model.config.hideLabel == 1; @@ -8,14 +8,14 @@ //set the config equal to our prevalue config $scope.model.config = $scope.model.config.archetypeConfig; - + //ini the model - $scope.model.value = $scope.model.value || { fieldsets: [getEmptyRenderFieldset($scope.model.config.fieldsets[0])] }; + $scope.model.value = $scope.model.value || getDefaultModel($scope.model.config); //ini the render model $scope.archetypeRenderModel = {}; initArchetypeRenderModel(); - + //helper to get $eval the labelTemplate $scope.getFieldsetTitle = function(fieldsetConfigModel, fieldsetIndex) { var fieldset = $scope.archetypeRenderModel.fieldsets[fieldsetIndex]; @@ -100,8 +100,9 @@ //helper that returns if an item can be removed $scope.canRemove = function () - { - return countVisible() > 1; + { + return countVisible() > 1 + || $scope.model.config.startWithAddButton; } //helper that returns if an item can be sorted @@ -110,6 +111,12 @@ return countVisible() > 1; } + //helpers for determining if the add button should be shown + $scope.showAddButton = function () { + return $scope.model.config.startWithAddButton + && countVisible() === 0; + } + //helper, ini the render model from the server (model.value) function initArchetypeRenderModel() { $scope.archetypeRenderModel = removeNulls($scope.model.value); @@ -119,7 +126,7 @@ fieldset.remove = false; fieldset.collapse = false; fieldset.isValid = true; - }); + }); } //helper to get the correct fieldset from config @@ -136,7 +143,7 @@ }); return (typeof property !== 'undefined') ? property.value : ''; }; - + //helper for expanding/collapsing fieldsets $scope.focusFieldset = function(fieldset){ fixDisableSelection(); @@ -144,30 +151,30 @@ if (!$scope.model.config.enableCollapsing) { return; } - + var iniState; - + if(fieldset) { iniState = fieldset.collapse; } - + _.each($scope.archetypeRenderModel.fieldsets, function(fieldset){ fieldset.collapse = true; }); - + if(!fieldset && $scope.archetypeRenderModel.fieldsets.length == 1 && $scope.archetypeRenderModel.fieldsets[0].remove == false) { $scope.archetypeRenderModel.fieldsets[0].collapse = false; return; } - + if(iniState && fieldset) { fieldset.collapse = !iniState; } } - + //ini the fieldset expand/collapse $scope.focusFieldset(); @@ -241,7 +248,7 @@ if(propertyConfig){ delete property.isValid; } - else + else { //need to remove the whole property tempFieldset.properties.splice(index, 1); @@ -253,10 +260,17 @@ } } + // helper to get initial model if none was provided + function getDefaultModel(config) { + if (config.startWithAddButton) + return { fieldsets: [] }; + + return { fieldsets: [getEmptyRenderFieldset(config.fieldsets[0])] }; + } + //helper to add an empty fieldset to the render model - function getEmptyRenderFieldset (fieldsetModel) - { - return JSON.parse('{"alias": "' + fieldsetModel.alias + '", "remove": false, "isValid": true, "properties": []}'); + function getEmptyRenderFieldset (fieldsetModel) { + return {alias: fieldsetModel.alias, remove: false, isValid: true, properties: []}; } //helper to ensure no nulls make it into the model @@ -268,7 +282,7 @@ removeNulls(model); } }); - + return model; } } @@ -277,9 +291,9 @@ function fixDisableSelection() { $timeout(function() { $('.archetypeEditor .controls') - .bind('mousedown.ui-disableSelection selectstart.ui-disableSelection', function(e) { + .bind('mousedown.ui-disableSelection selectstart.ui-disableSelection', function(e) { e.stopImmediatePropagation(); - }); + }); }, 1000); } @@ -307,7 +321,7 @@ { notificationsService.warning("Cannot Save Document", "The document could not be saved because of missing required fields.") } - else + else { syncModelToRenderModel(); } @@ -316,7 +330,7 @@ //custom js if ($scope.model.config.customJsPath) { assetsService.loadJs($scope.model.config.customJsPath); - } + } //archetype css assetsService.loadCss("/App_Plugins/Archetype/css/archetype.css"); diff --git a/app/directives/archetypeproperty.js b/app/directives/archetypeproperty.js index 5286fca..a97955e 100644 --- a/app/directives/archetypeproperty.js +++ b/app/directives/archetypeproperty.js @@ -51,7 +51,7 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c var configFieldsetModel = getFieldsetByAlias(scope.archetypeConfig.fieldsets, scope.fieldset.alias); var view = ""; var label = configFieldsetModel.properties[scope.propertyConfigIndex].label; - var dataTypeId = configFieldsetModel.properties[scope.propertyConfigIndex].dataTypeId; + var dataTypeGuid = configFieldsetModel.properties[scope.propertyConfigIndex].dataTypeGuid; var config = null; var alias = configFieldsetModel.properties[scope.propertyConfigIndex].alias; var defaultValue = configFieldsetModel.properties[scope.propertyConfigIndex].value; @@ -61,7 +61,7 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c defaultValue = jsonOrString(defaultValue, scope.archetypeConfig.developerMode, "defaultValue"); //grab info for the selected datatype, prepare for view - archetypePropertyEditorResource.getDataType(dataTypeId).then(function (data) { + archetypePropertyEditorResource.getDataType(dataTypeGuid).then(function (data) { //transform preValues array into object expected by propertyeditor views var configObj = {}; _.each(data.preValues, function(p) { @@ -75,7 +75,7 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c //load in the DefaultPreValues for the PropertyEditor, if any var defaultConfigObj = {}; - if (propertyEditor.hasOwnProperty('defaultPreValues')) { + if (propertyEditor.hasOwnProperty('defaultPreValues') && propertyEditor.defaultPreValues != null && propertyEditor.defaultPreValues.length > 0) { _.each(propertyEditor.defaultPreValues, function(p) { _.extend(defaultConfigObj, p) }); diff --git a/app/less/archetype.less b/app/less/archetype.less index eb7370f..215aac8 100644 --- a/app/less/archetype.less +++ b/app/less/archetype.less @@ -36,7 +36,7 @@ cursor: pointer; label { - span { + span { text-decoration: underline; } &:hover { @@ -297,6 +297,14 @@ } } +.archetypeEditor .archetypeAddButton:hover { + text-decoration: none; + + .archetypeAddButtonText { + text-decoration: underline; + } +} + .ui-sortable-placeholder { visibility: visible !important; background-color: #d0e7f1 !important; diff --git a/app/resources/propertyeditor.js b/app/resources/propertyeditor.js index 0a1cc9b..13b6afb 100644 --- a/app/resources/propertyeditor.js +++ b/app/resources/propertyeditor.js @@ -3,24 +3,20 @@ angular.module('umbraco.resources').factory('archetypePropertyEditorResource', f getAllDataTypes: function() { // Hack - grab DataTypes from Tree API, as `dataTypeService.getAll()` isn't implemented yet return umbRequestHelper.resourcePromise( - $http.get("/umbraco/backoffice/UmbracoTrees/DataTypeTree/GetNodes?id=-1&application=developer&tree=&isDialog=false"), 'Failed to retrieve datatypes from tree service' - ).then(function (data) { - return data.map(function(d) { - return { "id": d.id, "name": d.name } - }); - }); + $http.get("/umbraco/backoffice/ArchetypeApi/ArchetypeDataType/GetAll"), 'Failed to retrieve datatypes from tree service' + ); }, - getDataType: function(id) { + getDataType: function(guid) { return umbRequestHelper.resourcePromise( - $http.get("/umbraco/backoffice/ArchetypeApi/ArchetypeDataType/GetById?id=" + id), 'Failed to retrieve datatype' + $http.get("/umbraco/backoffice/ArchetypeApi/ArchetypeDataType/GetByGuid?guid=" + guid), 'Failed to retrieve datatype' ); }, getPropertyEditorMapping: function(alias) { return umbRequestHelper.resourcePromise( - $http.get("/App_plugins/Archetype/js/propertyEditors.views.js"), 'Failed to retrieve datatype mappings' + $http.get("/umbraco/backoffice/ArchetypeApi/ArchetypeDataType/GetAllPropertyEditors"), 'Failed to retrieve datatype mappings' ).then(function (data) { var result = _.find(data, function(d) { - return d.propertyEditorAlias === alias; + return d.alias === alias; }); if (result != null) diff --git a/app/views/archetype.config.html b/app/views/archetype.config.html index c80bf10..5f769b1 100644 --- a/app/views/archetype.config.html +++ b/app/views/archetype.config.html @@ -27,7 +27,7 @@ Properties - + @@ -37,7 +37,7 @@ - {{property.label}} ({{property.alias}}) - {{getDataTypeNameById(property.dataTypeId)}} + {{property.label}} ({{property.alias}}) - {{getDataTypeNameByGuid(property.dataTypeGuid)}} @@ -54,7 +54,7 @@ Datatype - + Default Value @@ -81,6 +81,10 @@ + + Start With Add Button?Empty property shows an add button instead of providing a default fieldset. + + Hide Fieldset Controls?Hides the fieldset add/remove/sort controls. @@ -96,11 +100,11 @@ Enable Multiple Fieldsets?Allows multiple types of fieldsets within this archetype. - + Enable Collapsing?Allows multiple types of fieldsets within this archetype. - + Hide Fieldset Toolbar?Hides the fieldset toolbar that appears when more than one fieldset model appears. diff --git a/app/views/archetype.html b/app/views/archetype.html index b565237..bf31438 100644 --- a/app/views/archetype.html +++ b/app/views/archetype.html @@ -9,7 +9,7 @@ - + @@ -24,7 +24,7 @@ - + @@ -49,4 +49,11 @@ + + + + + Add + +