Prune/remove indentation from JSON property values (#11806)

* Use Formatting.None for JSON property data in default value editor

* Use Formatting.None for JSON property data in custom value editors

* Use Formatting.None for JSON property data in Nested Content and Block List

* Use Formatting.None for JSON property tags

* Use Formatting.None for JSON configuration data

* Use Formatting.None in custom JSON converter

* Ensure empty tags and complex editor values are not stored

* Fix NestedContentPropertyComponentTests

* Do not store empty property data

* Use Formatting.None and don't store configured crops (without coordinates)

* Fix JSON deserialization of tags value
This commit is contained in:
Ronald Barendse
2022-01-10 09:32:29 +01:00
committed by GitHub
parent 75bb8051bf
commit 2155062678
20 changed files with 281 additions and 269 deletions

View File

@@ -68,11 +68,13 @@ namespace Umbraco.Core.Models
switch (storageType)
{
case TagsStorageType.Csv:
property.SetValue(string.Join(delimiter.ToString(), currentTags.Union(trimmedTags)), culture); // csv string
property.SetValue(string.Join(delimiter.ToString(), currentTags.Union(trimmedTags)).NullOrWhiteSpaceAsNull(), culture); // csv string
break;
case TagsStorageType.Json:
property.SetValue(JsonConvert.SerializeObject(currentTags.Union(trimmedTags).ToArray()), culture); // json array
var updatedTags = currentTags.Union(trimmedTags).ToArray();
var updatedValue = updatedTags.Length == 0 ? null : JsonConvert.SerializeObject(updatedTags, Formatting.None);
property.SetValue(updatedValue, culture); // json array
break;
}
}
@@ -81,11 +83,12 @@ namespace Umbraco.Core.Models
switch (storageType)
{
case TagsStorageType.Csv:
property.SetValue(string.Join(delimiter.ToString(), trimmedTags), culture); // csv string
property.SetValue(string.Join(delimiter.ToString(), trimmedTags).NullOrWhiteSpaceAsNull(), culture); // csv string
break;
case TagsStorageType.Json:
property.SetValue(JsonConvert.SerializeObject(trimmedTags), culture); // json array
var updatedValue = trimmedTags.Length == 0 ? null : JsonConvert.SerializeObject(trimmedTags, Formatting.None);
property.SetValue(updatedValue, culture); // json array
break;
}
}
@@ -121,11 +124,13 @@ namespace Umbraco.Core.Models
switch (storageType)
{
case TagsStorageType.Csv:
property.SetValue(string.Join(delimiter.ToString(), currentTags.Except(trimmedTags)), culture); // csv string
property.SetValue(string.Join(delimiter.ToString(), currentTags.Except(trimmedTags)).NullOrWhiteSpaceAsNull(), culture); // csv string
break;
case TagsStorageType.Json:
property.SetValue(JsonConvert.SerializeObject(currentTags.Except(trimmedTags).ToArray()), culture); // json array
var updatedTags = currentTags.Except(trimmedTags).ToArray();
var updatedValue = updatedTags.Length == 0 ? null : JsonConvert.SerializeObject(updatedTags, Formatting.None);
property.SetValue(updatedValue, culture); // json array
break;
}
}
@@ -157,7 +162,7 @@ namespace Umbraco.Core.Models
case TagsStorageType.Json:
try
{
return JsonConvert.DeserializeObject<JArray>(value).Select(x => x.ToString().Trim());
return JsonConvert.DeserializeObject<string[]>(value).Select(x => x.Trim());
}
catch (JsonException)
{

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
@@ -59,11 +61,13 @@ namespace Umbraco.Core.PropertyEditors
foreach (var cultureVal in propVals)
{
// Remove keys from published value & any nested properties
var updatedPublishedVal = _formatPropertyValue(cultureVal.PublishedValue?.ToString(), onlyMissingKeys);
var publishedValue = cultureVal.PublishedValue is JToken jsonPublishedValue ? jsonPublishedValue.ToString(Formatting.None) : cultureVal.PublishedValue?.ToString();
var updatedPublishedVal = _formatPropertyValue(publishedValue, onlyMissingKeys).NullOrWhiteSpaceAsNull();
cultureVal.PublishedValue = updatedPublishedVal;
// Remove keys from edited/draft value & any nested properties
var updatedEditedVal = _formatPropertyValue(cultureVal.EditedValue?.ToString(), onlyMissingKeys);
var editedValue = cultureVal.EditedValue is JToken jsonEditedValue ? jsonEditedValue.ToString(Formatting.None) : cultureVal.EditedValue?.ToString();
var updatedEditedVal = _formatPropertyValue(editedValue, onlyMissingKeys).NullOrWhiteSpaceAsNull();
cultureVal.EditedValue = updatedEditedVal;
}
}

View File

@@ -126,6 +126,8 @@ namespace Umbraco.Core.PropertyEditors
/// </summary>
public static JsonSerializerSettings ConfigurationJsonSettings { get; } = new JsonSerializerSettings
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new ConfigurationCustomContractResolver(),
Converters = new List<JsonConverter>(new[]{new FuzzyBooleanConverter()})
};

View File

@@ -145,8 +145,18 @@ namespace Umbraco.Core.PropertyEditors
/// <returns></returns>
internal Attempt<object> TryConvertValueToCrlType(object value)
{
if (value is JValue)
value = value.ToString();
if (value is JToken jsonValue)
{
if (jsonValue is JContainer && jsonValue.HasValues == false)
{
// Empty JSON array/object
value = null;
}
else
{
value = jsonValue.ToString(Formatting.None);
}
}
//this is a custom check to avoid any errors, if it's a string and it's empty just make it null
if (value is string s && string.IsNullOrWhiteSpace(s))
@@ -187,6 +197,7 @@ namespace Umbraco.Core.PropertyEditors
default:
throw new ArgumentOutOfRangeException();
}
return value.TryConvertTo(valueType);
}
@@ -222,6 +233,7 @@ namespace Umbraco.Core.PropertyEditors
Current.Logger.Warn<DataValueEditor,object,ValueStorageType>("The value {EditorValue} cannot be converted to the type {StorageTypeValue}", editorValue.Value, ValueTypes.ToStorageType(ValueType));
return null;
}
return result.Result;
}

View File

@@ -20,9 +20,10 @@ namespace Umbraco.Core.Serialization
{
return reader.Value;
}
// Load JObject from stream
JObject jObject = JObject.Load(reader);
return jObject.ToString();
return jObject.ToString(Formatting.None);
}
public override bool CanConvert(Type objectType)

View File

@@ -14,8 +14,7 @@ namespace Umbraco.Tests.PropertyEditors
private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};
private const string _contentGuid1 = "036ce82586a64dfba2d523a99ed80f58";

View File

@@ -1,10 +1,7 @@
using Newtonsoft.Json;
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Web.Compose;
namespace Umbraco.Tests.PropertyEditors
@@ -13,6 +10,11 @@ namespace Umbraco.Tests.PropertyEditors
[TestFixture]
public class NestedContentPropertyComponentTests
{
private static void AreEqualJson(string expected, string actual)
{
Assert.AreEqual(JToken.Parse(expected), JToken.Parse(actual));
}
[Test]
public void Invalid_Json()
{
@@ -29,17 +31,18 @@ namespace Umbraco.Tests.PropertyEditors
Func<Guid> guidFactory = () => guids[guidCounter++];
var json = @"[
{""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1"",""ncContentTypeAlias"":""nested"",""text"":""woot""},
{""key"":""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",""name"":""Item 2"",""ncContentTypeAlias"":""nested"",""text"":""zoot""}
]";
{""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1"",""ncContentTypeAlias"":""nested"",""text"":""woot""},
{""key"":""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",""name"":""Item 2"",""ncContentTypeAlias"":""nested"",""text"":""zoot""}
]";
var expected = json
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
.Replace("d8e214d8-c5a5-4b45-9b51-4050dd47f5fa", guids[1].ToString());
var component = new NestedContentPropertyComponent();
var result = component.CreateNestedContentKeys(json, false, guidFactory);
var actual = component.CreateNestedContentKeys(json, false, guidFactory);
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
AreEqualJson(expected, actual);
}
[Test]
@@ -50,29 +53,27 @@ namespace Umbraco.Tests.PropertyEditors
Func<Guid> guidFactory = () => guids[guidCounter++];
var json = @"[{
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"": [{
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""fbde4288-8382-4e13-8933-ed9c160de050"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""text"",
""text"": ""zoot""
}
]
}
]";
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"": [{
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""fbde4288-8382-4e13-8933-ed9c160de050"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""text"",
""text"": ""zoot""
}]
}]";
var expected = json
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
@@ -81,9 +82,9 @@ namespace Umbraco.Tests.PropertyEditors
.Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString());
var component = new NestedContentPropertyComponent();
var result = component.CreateNestedContentKeys(json, false, guidFactory);
var actual = component.CreateNestedContentKeys(json, false, guidFactory);
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
AreEqualJson(expected, actual);
}
[Test]
@@ -95,7 +96,8 @@ namespace Umbraco.Tests.PropertyEditors
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
// and this is how to do that, the result will also include quotes around it.
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
var subJsonEscaped = JsonConvert.ToString(JToken.Parse(@"
[{
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
@@ -105,22 +107,20 @@ namespace Umbraco.Tests.PropertyEditors
""name"": ""Item 2"",
""ncContentTypeAlias"": ""text"",
""text"": ""zoot""
}
]").ToString());
}]").ToString(Formatting.None));
var json = @"[{
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + subJsonEscaped + @"
}
]";
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + subJsonEscaped + @"
}]";
var expected = json
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
@@ -129,9 +129,9 @@ namespace Umbraco.Tests.PropertyEditors
.Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString());
var component = new NestedContentPropertyComponent();
var result = component.CreateNestedContentKeys(json, false, guidFactory);
var actual = component.CreateNestedContentKeys(json, false, guidFactory);
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
AreEqualJson(expected, actual);
}
[Test]
@@ -143,7 +143,7 @@ namespace Umbraco.Tests.PropertyEditors
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
// and this is how to do that, the result will also include quotes around it.
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
var subJsonEscaped = JsonConvert.ToString(JToken.Parse(@"[{
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
@@ -153,79 +153,74 @@ namespace Umbraco.Tests.PropertyEditors
""name"": ""Item 2"",
""ncContentTypeAlias"": ""text"",
""text"": ""zoot""
}
]").ToString());
}]").ToString(Formatting.None));
// Complex editor such as the grid
var complexEditorJsonEscaped = @"{
""name"": ""1 column layout"",
""sections"": [
{
""grid"": ""12"",
""rows"": [
{
""name"": ""Article"",
""id"": ""b4f6f651-0de3-ef46-e66a-464f4aaa9c57"",
""areas"": [
{
""grid"": ""4"",
""controls"": [
""name"": ""1 column layout"",
""sections"": [
{
""value"": ""I am quote"",
""editor"": {
""alias"": ""quote"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
},
{
""grid"": ""8"",
""controls"": [
{
""value"": ""Header"",
""editor"": {
""alias"": ""headline"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
},
{
""value"": " + subJsonEscaped + @",
""editor"": {
""alias"": ""madeUpNestedContent"",
""view"": ""madeUpNestedContentInGrid""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}]
}]
}";
""grid"": ""12"",
""rows"": [
{
""name"": ""Article"",
""id"": ""b4f6f651-0de3-ef46-e66a-464f4aaa9c57"",
""areas"": [
{
""grid"": ""4"",
""controls"": [{
""value"": ""I am quote"",
""editor"": {
""alias"": ""quote"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
},
{
""grid"": ""8"",
""controls"": [{
""value"": ""Header"",
""editor"": {
""alias"": ""headline"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
},
{
""value"": " + subJsonEscaped + @",
""editor"": {
""alias"": ""madeUpNestedContent"",
""view"": ""madeUpNestedContentInGrid""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}]
}]
}";
var json = @"[{
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + complexEditorJsonEscaped + @"
}
]";
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + complexEditorJsonEscaped + @"
}]";
var expected = json
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
@@ -234,12 +229,11 @@ namespace Umbraco.Tests.PropertyEditors
.Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString());
var component = new NestedContentPropertyComponent();
var result = component.CreateNestedContentKeys(json, false, guidFactory);
var actual = component.CreateNestedContentKeys(json, false, guidFactory);
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
AreEqualJson(expected, actual);
}
[Test]
public void No_Nesting_Generates_Keys_For_Missing_Items()
{
@@ -248,18 +242,18 @@ namespace Umbraco.Tests.PropertyEditors
Func<Guid> guidFactory = () => guids[guidCounter++];
var json = @"[
{""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1 my key wont change"",""ncContentTypeAlias"":""nested"",""text"":""woot""},
{""name"":""Item 2 was copied and has no key prop"",""ncContentTypeAlias"":""nested"",""text"":""zoot""}
]";
{""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1 my key wont change"",""ncContentTypeAlias"":""nested"",""text"":""woot""},
{""name"":""Item 2 was copied and has no key prop"",""ncContentTypeAlias"":""nested"",""text"":""zoot""}
]";
var component = new NestedContentPropertyComponent();
var result = component.CreateNestedContentKeys(json, true, guidFactory);
// Ensure the new GUID is put in a key into the JSON
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString()));
Assert.IsTrue(result.Contains(guids[0].ToString()));
// Ensure that the original key is NOT changed/modified & still exists
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains("04a6dba8-813c-4144-8aca-86a3f24ebf08"));
Assert.IsTrue(result.Contains("04a6dba8-813c-4144-8aca-86a3f24ebf08"));
}
[Test]
@@ -271,7 +265,7 @@ namespace Umbraco.Tests.PropertyEditors
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
// and this is how to do that, the result will also include quotes around it.
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
var subJsonEscaped = JsonConvert.ToString(JToken.Parse(@"[{
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
@@ -279,29 +273,27 @@ namespace Umbraco.Tests.PropertyEditors
""name"": ""Nested Item 2 was copied and has no key"",
""ncContentTypeAlias"": ""text"",
""text"": ""zoot""
}
]").ToString());
}]").ToString(Formatting.None));
var json = @"[{
""name"": ""Item 1 was copied and has no key"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + subJsonEscaped + @"
}
]";
""name"": ""Item 1 was copied and has no key"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
""name"": ""Item 2"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + subJsonEscaped + @"
}]";
var component = new NestedContentPropertyComponent();
var result = component.CreateNestedContentKeys(json, true, guidFactory);
// Ensure the new GUID is put in a key into the JSON for each item
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString()));
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[1].ToString()));
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[2].ToString()));
Assert.IsTrue(result.Contains(guids[0].ToString()));
Assert.IsTrue(result.Contains(guids[1].ToString()));
Assert.IsTrue(result.Contains(guids[2].ToString()));
}
[Test]
@@ -313,7 +305,7 @@ namespace Umbraco.Tests.PropertyEditors
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
// and this is how to do that, the result will also include quotes around it.
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
var subJsonEscaped = JsonConvert.ToString(JToken.Parse(@"[{
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
@@ -322,85 +314,80 @@ namespace Umbraco.Tests.PropertyEditors
""name"": ""Nested Item 2 was copied and has no key"",
""ncContentTypeAlias"": ""text"",
""text"": ""zoot""
}
]").ToString());
}]").ToString(Formatting.None));
// Complex editor such as the grid
var complexEditorJsonEscaped = @"{
""name"": ""1 column layout"",
""sections"": [
{
""grid"": ""12"",
""rows"": [
{
""name"": ""Article"",
""id"": ""b4f6f651-0de3-ef46-e66a-464f4aaa9c57"",
""areas"": [
{
""grid"": ""4"",
""controls"": [
""name"": ""1 column layout"",
""sections"": [
{
""value"": ""I am quote"",
""editor"": {
""alias"": ""quote"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
},
{
""grid"": ""8"",
""controls"": [
{
""value"": ""Header"",
""editor"": {
""alias"": ""headline"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
},
{
""value"": " + subJsonEscaped + @",
""editor"": {
""alias"": ""madeUpNestedContent"",
""view"": ""madeUpNestedContentInGrid""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}]
}]
}";
""grid"": ""12"",
""rows"": [
{
""name"": ""Article"",
""id"": ""b4f6f651-0de3-ef46-e66a-464f4aaa9c57"",
""areas"": [
{
""grid"": ""4"",
""controls"": [{
""value"": ""I am quote"",
""editor"": {
""alias"": ""quote"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
},
{
""grid"": ""8"",
""controls"": [{
""value"": ""Header"",
""editor"": {
""alias"": ""headline"",
""view"": ""textstring""
},
""styles"": null,
""config"": null
},
{
""value"": " + subJsonEscaped + @",
""editor"": {
""alias"": ""madeUpNestedContent"",
""view"": ""madeUpNestedContentInGrid""
},
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}],
""styles"": null,
""config"": null
}]
}]
}";
var json = @"[{
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""name"": ""Item 2 was copied and has no key"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + complexEditorJsonEscaped + @"
}
]";
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
""name"": ""Item 1"",
""ncContentTypeAlias"": ""text"",
""text"": ""woot""
}, {
""name"": ""Item 2 was copied and has no key"",
""ncContentTypeAlias"": ""list"",
""text"": ""zoot"",
""subItems"":" + complexEditorJsonEscaped + @"
}]";
var component = new NestedContentPropertyComponent();
var result = component.CreateNestedContentKeys(json, true, guidFactory);
// Ensure the new GUID is put in a key into the JSON for each item
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString()));
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[1].ToString()));
Assert.IsTrue(result.Contains(guids[0].ToString()));
Assert.IsTrue(result.Contains(guids[1].ToString()));
}
}
}

View File

@@ -63,7 +63,7 @@ namespace Umbraco.Web.Compose
UpdateBlockListRecursively(blockListValue, createGuid);
return JsonConvert.SerializeObject(blockListValue.BlockValue);
return JsonConvert.SerializeObject(blockListValue.BlockValue, Formatting.None);
}
private void UpdateBlockListRecursively(BlockEditorData blockListData, Func<Guid> createGuid)

View File

@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
using Umbraco.Web.PropertyEditors;
namespace Umbraco.Web.Compose
@@ -47,7 +43,7 @@ namespace Umbraco.Web.Compose
UpdateNestedContentKeysRecursively(complexEditorValue, onlyMissingKeys, createGuid);
return complexEditorValue.ToString();
return complexEditorValue.ToString(Formatting.None);
}
private void UpdateNestedContentKeysRecursively(JToken json, bool onlyMissingKeys, Func<Guid> createGuid)
@@ -80,7 +76,7 @@ namespace Umbraco.Web.Compose
var parsed = JToken.Parse(propVal);
UpdateNestedContentKeysRecursively(parsed, onlyMissingKeys, createGuid);
// set the value to the updated one
prop.Value = parsed.ToString();
prop.Value = parsed.ToString(Formatting.None);
}
}
}

View File

@@ -234,7 +234,7 @@ namespace Umbraco.Web.PropertyEditors
MapBlockItemData(blockEditorData.BlockValue.SettingsData);
// return json
return JsonConvert.SerializeObject(blockEditorData.BlockValue);
return JsonConvert.SerializeObject(blockEditorData.BlockValue, Formatting.None);
}
#endregion

View File

@@ -130,7 +130,7 @@ namespace Umbraco.Web.PropertyEditors
if (id >= nextId) nextId = id + 1;
var label = item.Property("label")?.Value?.Value<string>();
value = JsonConvert.SerializeObject(new { value, label });
value = JsonConvert.SerializeObject(new { value, label }, Formatting.None);
output.Items.Add(new ValueListConfiguration.ValueListItem { Id = id, Value = value });
}

View File

@@ -142,7 +142,7 @@ namespace Umbraco.Web.PropertyEditors
}
// Convert back to raw JSON for persisting
return JsonConvert.SerializeObject(grid);
return JsonConvert.SerializeObject(grid, Formatting.None);
}
/// <summary>

View File

@@ -1,16 +1,14 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Media;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Services;
using Umbraco.Web.Media;
@@ -170,7 +168,7 @@ namespace Umbraco.Web.PropertyEditors
var sourcePath = _mediaFileSystem.GetRelativePath(src);
var copyPath = _mediaFileSystem.CopyFile(args.Copy, property.PropertyType, sourcePath);
jo["src"] = _mediaFileSystem.GetUrl(copyPath);
args.Copy.SetValue(property.Alias, jo.ToString(), propertyValue.Culture, propertyValue.Segment);
args.Copy.SetValue(property.Alias, jo.ToString(Formatting.None), propertyValue.Culture, propertyValue.Segment);
isUpdated = true;
}
}
@@ -241,17 +239,12 @@ namespace Umbraco.Web.PropertyEditors
// it can happen when an image is uploaded via the folder browser, in which case
// the property value will be the file source eg '/media/23454/hello.jpg' and we
// are fixing that anomaly here - does not make any sense at all but... bah...
var dt = _dataTypeService.GetDataType(property.PropertyType.DataTypeId);
var config = dt?.ConfigurationAs<ImageCropperConfiguration>();
src = svalue;
var json = new
{
src = svalue,
crops = config == null ? Array.Empty<ImageCropperConfiguration.Crop>() : config.Crops
};
property.SetValue(JsonConvert.SerializeObject(json), pvalue.Culture, pvalue.Segment);
property.SetValue(JsonConvert.SerializeObject(new
{
src = svalue
}, Formatting.None), pvalue.Culture, pvalue.Segment);
}
else
{

View File

@@ -190,6 +190,10 @@ namespace Umbraco.Web.PropertyEditors
{
src = val,
crops = crops
}, new JsonSerializerSettings()
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore
});
}
}

View File

@@ -123,22 +123,26 @@ namespace Umbraco.Web.PropertyEditors
private static readonly JsonSerializerSettings LinkDisplayJsonSerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore
};
public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
var value = editorValue.Value?.ToString();
if (string.IsNullOrEmpty(value))
{
return string.Empty;
return null;
}
try
{
var links = JsonConvert.DeserializeObject<List<LinkDisplay>>(value);
if (links.Count == 0)
return null;
return JsonConvert.SerializeObject(
from link in JsonConvert.DeserializeObject<List<LinkDisplay>>(value)
from link in links
select new MultiUrlPickerValueEditor.LinkDto
{
Name = link.Name,
@@ -146,8 +150,8 @@ namespace Umbraco.Web.PropertyEditors
Target = link.Target,
Udi = link.Udi,
Url = link.Udi == null ? link.Url : null, // only save the URL for external links
}, LinkDisplayJsonSerializerSettings
);
},
LinkDisplayJsonSerializerSettings);
}
catch (Exception ex)
{

View File

@@ -60,7 +60,7 @@ namespace Umbraco.Web.PropertyEditors
public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
var asArray = editorValue.Value as JArray;
if (asArray == null)
if (asArray == null || asArray.HasValues == false)
{
return null;
}

View File

@@ -49,14 +49,18 @@ namespace Umbraco.Web.PropertyEditors
public override object FromEditor(Core.Models.Editors.ContentPropertyData editorValue, object currentValue)
{
var json = editorValue.Value as JArray;
if (json == null)
if (json == null || json.HasValues == false)
{
return null;
}
var values = json.Select(item => item.Value<string>()).ToArray();
if (values.Length == 0)
{
return null;
}
return JsonConvert.SerializeObject(values);
return JsonConvert.SerializeObject(values, Formatting.None);
}
}
}

View File

@@ -103,7 +103,7 @@ namespace Umbraco.Web.PropertyEditors
var rows = _nestedContentValues.GetPropertyValues(propertyValue);
if (rows.Count == 0)
return string.Empty;
return null;
foreach (var row in rows.ToList())
{
@@ -134,7 +134,7 @@ namespace Umbraco.Web.PropertyEditors
}
}
return JsonConvert.SerializeObject(rows).ToXmlString<string>();
return JsonConvert.SerializeObject(rows, Formatting.None).ToXmlString<string>();
}
#endregion
@@ -229,7 +229,7 @@ namespace Umbraco.Web.PropertyEditors
var rows = _nestedContentValues.GetPropertyValues(editorValue.Value);
if (rows.Count == 0)
return string.Empty;
return null;
foreach (var row in rows.ToList())
{
@@ -254,8 +254,9 @@ namespace Umbraco.Web.PropertyEditors
}
// return json
return JsonConvert.SerializeObject(rows);
return JsonConvert.SerializeObject(rows, Formatting.None);
}
#endregion
public IEnumerable<UmbracoEntityReference> GetReferences(object value)

View File

@@ -142,7 +142,7 @@ namespace Umbraco.Web.PropertyEditors
var editorValueWithMediaUrlsRemoved = _imageSourceParser.RemoveImageSources(parseAndSavedTempImages);
var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved);
return parsed;
return parsed.NullOrWhiteSpaceAsNull();
}
/// <summary>

View File

@@ -52,7 +52,7 @@ namespace Umbraco.Web.PropertyEditors
if (editorValue.Value is JArray json)
{
return json.Select(x => x.Value<string>());
return json.HasValues ? json.Select(x => x.Value<string>()) : null;
}
if (string.IsNullOrWhiteSpace(value) == false)