Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c9b7692f1 | |||
| 51223d4ac7 | |||
| 1d5f91964f | |||
| 0accac26ee | |||
| 6527e66ff3 | |||
| 47e71067a1 | |||
| 969cc45e9b | |||
| 9ff5bfc907 | |||
| 7cdcb940bd | |||
| 75e0ac5d6d | |||
| ba6921fdb9 | |||
| 8624617ad4 | |||
| e46e5c279f | |||
| a9dc79e4ff | |||
| 485c6cb6a1 | |||
| 8e7eda9276 | |||
| 96d70bc1a9 | |||
| 264208dcc7 | |||
| 077ab44dc8 | |||
| 7499395807 | |||
| d983b75be3 | |||
| 381875bc14 | |||
| 3944da57b1 | |||
| 0cbbd1c93e | |||
| 1bfab0f8a3 | |||
| 537abea717 | |||
| c8d9b04a57 | |||
| 32d0d199a3 | |||
| 715776771a | |||
| 4785c85b84 | |||
| 712ca3cd76 | |||
| 43a7202194 | |||
| 9a21ab0ef4 | |||
| a6b1abaecc | |||
| 258b0859ab | |||
| cee7d73b01 | |||
| 1e12b82742 | |||
| 7b5d9b4dd5 | |||
| 766ae0a8df | |||
| 43e1855b2c | |||
| cbec133186 | |||
| 23735fdf59 | |||
| 8c005b2ec9 | |||
| bfb1cc6abc | |||
| ea0d641f25 | |||
| 67311836c8 | |||
| 22d596e827 | |||
| b42306e741 |
+3
-1
@@ -55,6 +55,7 @@ module.exports = function(grunt) {
|
||||
'app/controllers/controller.js',
|
||||
'app/controllers/config.controller.js',
|
||||
'app/directives/archetypeproperty.js',
|
||||
'app/directives/archetypecustomview.js',
|
||||
'app/directives/localize.js',
|
||||
'app/services/localization.js',
|
||||
'app/resources/propertyeditor.js'
|
||||
@@ -66,7 +67,7 @@ module.exports = function(grunt) {
|
||||
copy: {
|
||||
html: {
|
||||
cwd: 'app/views/',
|
||||
src: ['archetype.html', 'archetype.config.html'],
|
||||
src: ['archetype.html', 'archetype.default.html', 'archetype.config.html'],
|
||||
dest: '<%= basePath %>/views',
|
||||
expand: true
|
||||
},
|
||||
@@ -190,6 +191,7 @@ module.exports = function(grunt) {
|
||||
stdout: true,
|
||||
verbosity: 'quiet',
|
||||
maxCpuCount: 4,
|
||||
version: 4.0,
|
||||
buildParameters: {
|
||||
WarningLevel: 2,
|
||||
NoWarn: 1607
|
||||
|
||||
@@ -2,6 +2,8 @@ Archetype
|
||||
=========
|
||||

|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
Install the selected <a href='https://github.com/imulus/Archetype/releases'>release</a> through the Umbraco package installer or via <a href='http://www.nuget.org/packages/Archetype/'>NuGet</a>.
|
||||
|
||||
|
||||
@@ -222,6 +222,10 @@
|
||||
<Compile Include="Models\FieldsetTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PropertyValueConverter\PropertyValueConverterTests.cs" />
|
||||
<Compile Include="Serialization\ArchetypeJsonConverterComplexModelTest.cs" />
|
||||
<Compile Include="Serialization\ArchetypeJsonConverterTest.cs" />
|
||||
<Compile Include="Serialization\JsonTestStrings.cs" />
|
||||
<Compile Include="Serialization\JsonTestModels.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
@@ -234,6 +238,7 @@
|
||||
<Name>Archetype.Umbraco</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
using System.Linq;
|
||||
using Archetype.PropertyConverters;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Archetype.Tests.Serialization
|
||||
{
|
||||
[TestFixture]
|
||||
public class ArchetypeJsonConverterComplexModelTest
|
||||
{
|
||||
private TextList _textList;
|
||||
private Captions _captions;
|
||||
private PageDetails _pageDetails;
|
||||
|
||||
private SlideShow _slides;
|
||||
private Seo _seo;
|
||||
private TextPageList _textPages;
|
||||
private PageList _pages;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
InitComplexModels();
|
||||
InitComplexTreeModel();
|
||||
}
|
||||
|
||||
#region complex nested model tests
|
||||
|
||||
[Test]
|
||||
public void PageDetailsModel_Serializes_To_Archetype_Property()
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(_pageDetails, Formatting.Indented);
|
||||
Assert.AreEqual(JsonTestStrings._PAGE_DETAILS_JSON, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertComplexModelToArchetype()
|
||||
{
|
||||
var converter = new ArchetypeValueConverter();
|
||||
var json = JsonConvert.SerializeObject(_pageDetails, Formatting.Indented);
|
||||
var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false);
|
||||
|
||||
Assert.NotNull(archetype);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeComplexModelFromArchetype()
|
||||
{
|
||||
var result = JsonConvert.DeserializeObject<PageDetails>(JsonTestStrings._PAGE_DETAILS_JSON);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<PageDetails>(result);
|
||||
|
||||
Assert.AreEqual("2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453", result.Pages);
|
||||
Assert.AreEqual("First Page", result.Captions.TextStringArray.ElementAt(0).TextString);
|
||||
Assert.AreEqual("Second Page", result.Captions.TextStringArray.ElementAt(1).TextString);
|
||||
Assert.AreEqual("Third Page", result.Captions.TextStringArray.ElementAt(2).TextString);
|
||||
Assert.AreEqual("Fourth Page", result.Captions.TextStringArray.ElementAt(3).TextString);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeThenDeserializeComplexModelFromArchetype()
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(_pageDetails);
|
||||
var result = JsonConvert.DeserializeObject<PageDetails>(json);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<PageDetails>(result);
|
||||
|
||||
Assert.AreEqual(_pageDetails.Pages, result.Pages);
|
||||
Assert.AreEqual(_pageDetails.Captions.TextStringArray.ElementAt(0).TextString, result.Captions.TextStringArray.ElementAt(0).TextString);
|
||||
Assert.AreEqual(_pageDetails.Captions.TextStringArray.ElementAt(1).TextString, result.Captions.TextStringArray.ElementAt(1).TextString);
|
||||
Assert.AreEqual(_pageDetails.Captions.TextStringArray.ElementAt(2).TextString, result.Captions.TextStringArray.ElementAt(2).TextString);
|
||||
Assert.AreEqual(_pageDetails.Captions.TextStringArray.ElementAt(3).TextString, result.Captions.TextStringArray.ElementAt(3).TextString);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region complex nested tree model tests
|
||||
|
||||
[Test]
|
||||
public void ConvertComplexNestedModelToArchetype()
|
||||
{
|
||||
var converter = new ArchetypeValueConverter();
|
||||
var json = JsonConvert.SerializeObject(_pages, Formatting.Indented);
|
||||
var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false);
|
||||
|
||||
Assert.NotNull(archetype);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PagesModel_Serializes_To_Archetype_Property()
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(_pages, Formatting.Indented);
|
||||
Assert.AreEqual(JsonTestStrings._PAGES_JSON, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeComplexTreeModelFromArchetype()
|
||||
{
|
||||
var result = JsonConvert.DeserializeObject<PageList>(JsonTestStrings._PAGES_JSON);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<PageList>(result);
|
||||
|
||||
Assert.AreEqual("1,2,3,4,5,6,7,8", result.Pages.ElementAt(0).Media.Slides);
|
||||
Assert.AreEqual("1,2,3,4,5,6,7,8", result.Pages.ElementAt(1).Media.Slides);
|
||||
Assert.AreEqual("1,2,3,4,5,6,7,8", result.Pages.ElementAt(2).Media.Slides);
|
||||
|
||||
Assert.AreEqual("Test Meta Title", result.Pages.ElementAt(0).Seo.MetaTitle);
|
||||
Assert.AreEqual("Test Meta Description", result.Pages.ElementAt(0).Seo.MetaDescription);
|
||||
Assert.AreEqual("Test Meta Title", result.Pages.ElementAt(1).Seo.MetaTitle);
|
||||
Assert.AreEqual("Test Meta Description", result.Pages.ElementAt(1).Seo.MetaDescription);
|
||||
Assert.AreEqual("Test Meta Title", result.Pages.ElementAt(2).Seo.MetaTitle);
|
||||
Assert.AreEqual("Test Meta Description", result.Pages.ElementAt(2).Seo.MetaDescription);
|
||||
|
||||
Assert.AreEqual("Home Page Body", result.Pages.ElementAt(0).BodyText);
|
||||
Assert.AreEqual("Home Page", result.Pages.ElementAt(0).PageTitle);
|
||||
Assert.AreEqual("About us Page Body", result.Pages.ElementAt(1).BodyText);
|
||||
Assert.AreEqual("About us Page", result.Pages.ElementAt(1).PageTitle);
|
||||
Assert.AreEqual("Contact us Page Body", result.Pages.ElementAt(2).BodyText);
|
||||
Assert.AreEqual("Contact us Page", result.Pages.ElementAt(2).PageTitle);
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeThenDeserializeComplexTreeModelFromArchetype()
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(_pages);
|
||||
var result = JsonConvert.DeserializeObject<PageList>(json);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<PageList>(result);
|
||||
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(0).Media.Slides, result.Pages.ElementAt(0).Media.Slides);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(1).Media.Slides, result.Pages.ElementAt(1).Media.Slides);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(2).Media.Slides, result.Pages.ElementAt(2).Media.Slides);
|
||||
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(0).Seo.MetaTitle, result.Pages.ElementAt(0).Seo.MetaTitle);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(0).Seo.MetaDescription, result.Pages.ElementAt(0).Seo.MetaDescription);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(1).Seo.MetaTitle, result.Pages.ElementAt(1).Seo.MetaTitle);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(1).Seo.MetaDescription, result.Pages.ElementAt(1).Seo.MetaDescription);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(2).Seo.MetaTitle, result.Pages.ElementAt(2).Seo.MetaTitle);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(2).Seo.MetaDescription, result.Pages.ElementAt(2).Seo.MetaDescription);
|
||||
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(0).BodyText, result.Pages.ElementAt(0).BodyText);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(0).PageTitle, result.Pages.ElementAt(0).PageTitle);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(1).BodyText, result.Pages.ElementAt(1).BodyText);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(1).PageTitle, result.Pages.ElementAt(1).PageTitle);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(2).BodyText, result.Pages.ElementAt(2).BodyText);
|
||||
Assert.AreEqual(_pages.Pages.ElementAt(2).PageTitle, result.Pages.ElementAt(2).PageTitle);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region utility methods
|
||||
|
||||
private void InitComplexModels()
|
||||
{
|
||||
_textList = new TextList
|
||||
{
|
||||
new TextItem{TextString = "First Page"},
|
||||
new TextItem{TextString = "Second Page"},
|
||||
new TextItem{TextString = "Third Page"},
|
||||
new TextItem{TextString = "Fourth Page"}
|
||||
};
|
||||
|
||||
_captions = new Captions {TextStringArray = _textList};
|
||||
|
||||
_pageDetails = new PageDetails
|
||||
{
|
||||
Captions = _captions,
|
||||
Pages = "2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453"
|
||||
};
|
||||
}
|
||||
|
||||
private void InitComplexTreeModel()
|
||||
{
|
||||
_slides = new SlideShow{Slides = "1,2,3,4,5,6,7,8"};
|
||||
_seo = new Seo{MetaDescription = "Test Meta Description", MetaTitle = "Test Meta Title"};
|
||||
_textPages = new TextPageList
|
||||
{
|
||||
new TextPage()
|
||||
{
|
||||
PageTitle = "Home Page",
|
||||
BodyText = "Home Page Body",
|
||||
Media = _slides,
|
||||
Seo = _seo
|
||||
},
|
||||
new TextPage()
|
||||
{
|
||||
PageTitle = "About us Page",
|
||||
BodyText = "About us Page Body",
|
||||
Media = _slides,
|
||||
Seo = _seo
|
||||
},
|
||||
new TextPage()
|
||||
{
|
||||
PageTitle = "Contact us Page",
|
||||
BodyText = "Contact us Page Body",
|
||||
Media = _slides,
|
||||
Seo = _seo
|
||||
}
|
||||
};
|
||||
|
||||
_pages = new PageList
|
||||
{
|
||||
Pages = _textPages
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
using System;
|
||||
using Archetype.PropertyConverters;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Archetype.Tests.Serialization
|
||||
{
|
||||
[TestFixture]
|
||||
public class ArchetypeJsonConverterTest
|
||||
{
|
||||
private ContactDetails _contactDetails;
|
||||
private CompanyDetails _companyDetails;
|
||||
private AnnualStatement _annualStatement;
|
||||
private MergerDetails _mergerDetails;
|
||||
private UrlPicker _webSite;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_webSite = new UrlPicker
|
||||
{
|
||||
Url = "http://test.com",
|
||||
Title = "The Test Company",
|
||||
OpenInNewWindow = true
|
||||
};
|
||||
|
||||
_mergerDetails = new MergerDetails
|
||||
{
|
||||
MergerDate = new DateTime(2014,6,7,8,9,10),
|
||||
MergerValue = 12345676890.12m
|
||||
};
|
||||
|
||||
_contactDetails = new ContactDetails
|
||||
{
|
||||
Address = "Test Address",
|
||||
Email = "test@test.com",
|
||||
Fax = "000",
|
||||
Mobile = "000",
|
||||
Name = "Test",
|
||||
Telephone = "111",
|
||||
WebSite = _webSite
|
||||
};
|
||||
|
||||
_companyDetails = new CompanyDetails
|
||||
{
|
||||
Region = "Test Region",
|
||||
ContactDetails = _contactDetails
|
||||
};
|
||||
|
||||
_annualStatement = new AnnualStatement
|
||||
{
|
||||
FiscalYearStart = new DateTime(2013, 9, 1),
|
||||
FiscalYearEnd = new DateTime(2014, 8, 31),
|
||||
TotalShares = 345678,
|
||||
Sales = 123456700.89,
|
||||
Profit = 1123456.78m
|
||||
};
|
||||
}
|
||||
|
||||
#region serialization tests
|
||||
|
||||
[Test]
|
||||
public void MergerDetailsModel_Serializes_To_Archetype_Property()
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(_mergerDetails, Formatting.Indented);
|
||||
Assert.AreEqual(JsonTestStrings._MERGER_DETAILS_JSON, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContactDetailsModel_Serializes_To_Archetype_Property()
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(_contactDetails, Formatting.Indented);
|
||||
Assert.AreEqual(JsonTestStrings._CONTACT_DETAILS_JSON, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CompanyDetailsModel_Fieldset_Serializes_As_Expected()
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(_companyDetails, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(JsonTestStrings._COMPANY_DETAILS_JSON, result);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnnualStatementModel_Fieldset_Serializes_As_Expected()
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(_annualStatement, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(JsonTestStrings._ANNUAL_STATEMENT_JSON, result);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NullValues_Serialize_To_Empty_String()
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(new ContactDetails());
|
||||
|
||||
Assert.AreEqual(JsonTestStrings._NULL_VALUES_JSON, result);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertModelToArchetype()
|
||||
{
|
||||
var model = new ContactDetails
|
||||
{
|
||||
Address = "addr",
|
||||
Email = "email"
|
||||
};
|
||||
|
||||
var converter = new ArchetypeValueConverter();
|
||||
var json = JsonConvert.SerializeObject(model);
|
||||
var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false);
|
||||
|
||||
Assert.NotNull(archetype);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertNumericAndDateModelToArchetype()
|
||||
{
|
||||
var converter = new ArchetypeValueConverter();
|
||||
var json = JsonConvert.SerializeObject(_annualStatement);
|
||||
var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false);
|
||||
|
||||
Assert.NotNull(archetype);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertCompoundModelToArchetype()
|
||||
{
|
||||
var item1 = new ContactDetails
|
||||
{
|
||||
Address = "addr",
|
||||
Email = "email"
|
||||
};
|
||||
|
||||
var item2 = new ContactDetails
|
||||
{
|
||||
Address = "addr1",
|
||||
Name = "email2"
|
||||
};
|
||||
|
||||
var model = new AllContactDetails
|
||||
{
|
||||
UserDetails = item1,
|
||||
AdminDetails = item2
|
||||
};
|
||||
|
||||
var converter = new ArchetypeValueConverter();
|
||||
var json = JsonConvert.SerializeObject(model, Formatting.Indented);
|
||||
var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false);
|
||||
|
||||
Assert.NotNull(archetype);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertEnumerableModelToArchetype()
|
||||
{
|
||||
var item1 = new ContactDetails
|
||||
{
|
||||
Address = "addr",
|
||||
Email = "email"
|
||||
};
|
||||
|
||||
var item2 = new ContactDetails
|
||||
{
|
||||
Address = "addr1",
|
||||
Name = "email2"
|
||||
};
|
||||
|
||||
var model = new ContactDetailsList
|
||||
{
|
||||
item1,
|
||||
item2
|
||||
};
|
||||
|
||||
var converter = new ArchetypeValueConverter();
|
||||
var json = JsonConvert.SerializeObject(model, Formatting.Indented);
|
||||
var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false);
|
||||
|
||||
Assert.NotNull(archetype);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertNestedModelToArchetype()
|
||||
{
|
||||
var model = new CompanyDetails
|
||||
{
|
||||
Region = "Test Region",
|
||||
ContactDetails = new ContactDetails
|
||||
{
|
||||
Address = "addr1",
|
||||
Name = "email2"
|
||||
}
|
||||
};
|
||||
|
||||
var converter = new ArchetypeValueConverter();
|
||||
var json = JsonConvert.SerializeObject(model, Formatting.Indented);
|
||||
var archetype = (Archetype.Models.ArchetypeModel)converter.ConvertDataToSource(null, json, false);
|
||||
|
||||
Assert.NotNull(archetype);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region deserialization tests
|
||||
|
||||
[Test]
|
||||
public void DeserializeModelFromArchetype()
|
||||
{
|
||||
var result = JsonConvert.DeserializeObject<ContactDetails>(JsonTestStrings._CONTACT_DETAILS_JSON);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<ContactDetails>(result);
|
||||
|
||||
Assert.AreEqual("Test Address", result.Address);
|
||||
Assert.AreEqual("test@test.com", result.Email);
|
||||
Assert.AreEqual("000", result.Fax);
|
||||
Assert.AreEqual("000", result.Mobile);
|
||||
Assert.AreEqual("Test", result.Name);
|
||||
Assert.AreEqual("111", result.Telephone);
|
||||
Assert.AreEqual(_webSite.Content, result.WebSite.Content);
|
||||
Assert.AreEqual(_webSite.Media, result.WebSite.Media);
|
||||
Assert.AreEqual(_webSite.OpenInNewWindow, result.WebSite.OpenInNewWindow);
|
||||
Assert.AreEqual(_webSite.Title, result.WebSite.Title);
|
||||
Assert.AreEqual(_webSite.Url, result.WebSite.Url);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeNumericAndDateModelFromArchetype()
|
||||
{
|
||||
var result = JsonConvert.DeserializeObject<AnnualStatement>(JsonTestStrings._ANNUAL_STATEMENT_JSON);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<AnnualStatement>(result);
|
||||
|
||||
Assert.AreEqual(new DateTime(2013, 9, 1), result.FiscalYearStart);
|
||||
Assert.AreEqual(new DateTime(2014, 8, 31), result.FiscalYearEnd);
|
||||
Assert.IsNull(result.DividendPaymentDate);
|
||||
Assert.AreEqual(345678, result.TotalShares);
|
||||
Assert.AreEqual(123456700.89, result.Sales);
|
||||
Assert.AreEqual(1123456.78m, result.Profit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeNumericAndDateModel_NullableDate_HasValue_FromArchetype()
|
||||
{
|
||||
var annualStatement = new AnnualStatement
|
||||
{
|
||||
FiscalYearStart = new DateTime(2013, 9, 1),
|
||||
FiscalYearEnd = new DateTime(2014, 8, 31),
|
||||
DividendPaymentDate = new DateTime(2014,9,15,10,15,30),
|
||||
TotalShares = 345678,
|
||||
Sales = 123456700.89,
|
||||
Profit = 1123456.78m
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(annualStatement);
|
||||
var result = JsonConvert.DeserializeObject<AnnualStatement>(json);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<AnnualStatement>(result);
|
||||
|
||||
Assert.AreEqual(annualStatement.FiscalYearStart, result.FiscalYearStart);
|
||||
Assert.AreEqual(annualStatement.FiscalYearEnd, result.FiscalYearEnd);
|
||||
Assert.AreEqual(annualStatement.DividendPaymentDate, result.DividendPaymentDate);
|
||||
Assert.AreEqual(annualStatement.TotalShares, result.TotalShares);
|
||||
Assert.AreEqual(annualStatement.Sales, result.Sales);
|
||||
Assert.AreEqual(annualStatement.Profit, result.Profit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeCompoundModelFromArchetype()
|
||||
{
|
||||
var item1 = new ContactDetails
|
||||
{
|
||||
Address = "addr",
|
||||
Email = "email"
|
||||
};
|
||||
|
||||
var item2 = new ContactDetails
|
||||
{
|
||||
Address = "addr1",
|
||||
Name = "email2"
|
||||
};
|
||||
|
||||
var model = new AllContactDetails
|
||||
{
|
||||
UserDetails = item1,
|
||||
AdminDetails = item2
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(model, Formatting.Indented);
|
||||
var result = JsonConvert.DeserializeObject<AllContactDetails>(json);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<AllContactDetails>(result);
|
||||
|
||||
Assert.AreEqual(item1.Address, result.UserDetails.Address);
|
||||
Assert.AreEqual(item1.Email, result.UserDetails.Email);
|
||||
Assert.AreEqual(item2.Address, result.AdminDetails.Address);
|
||||
Assert.AreEqual(item2.Name, result.AdminDetails.Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeEnumerableModelFromArchetype()
|
||||
{
|
||||
var item1 = new ContactDetails
|
||||
{
|
||||
Address = "addr",
|
||||
Email = "email"
|
||||
};
|
||||
|
||||
var item2 = new ContactDetails
|
||||
{
|
||||
Address = "addr1",
|
||||
Name = "email2"
|
||||
};
|
||||
|
||||
var model = new ContactDetailsList
|
||||
{
|
||||
item1,
|
||||
item2
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(model, Formatting.Indented);
|
||||
var result = JsonConvert.DeserializeObject<ContactDetailsList>(json);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<ContactDetailsList>(result);
|
||||
Assert.AreEqual(result.Count, 2);
|
||||
|
||||
Assert.AreEqual(item1.Address, result[0].Address);
|
||||
Assert.AreEqual(item1.Email, result[0].Email);
|
||||
Assert.AreEqual(item2.Address, result[1].Address);
|
||||
Assert.AreEqual(item2.Name, result[1].Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeNestedModelFromArchetype()
|
||||
{
|
||||
var model = new CompanyDetails
|
||||
{
|
||||
Region = "Test Region",
|
||||
ContactDetails = new ContactDetails
|
||||
{
|
||||
Address = "addr1",
|
||||
Name = "email2"
|
||||
}
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(model, Formatting.Indented);
|
||||
var result = JsonConvert.DeserializeObject<CompanyDetails>(json);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.IsInstanceOf<CompanyDetails>(result);
|
||||
|
||||
Assert.AreEqual(model.Region, result.Region);
|
||||
Assert.AreEqual(model.ContactDetails.Address, result.ContactDetails.Address);
|
||||
Assert.AreEqual(model.ContactDetails.Name, result.ContactDetails.Name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Archetype.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Archetype.Tests.Serialization
|
||||
{
|
||||
#region json test Models
|
||||
|
||||
[AsArchetype("urlPicker")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class UrlPicker
|
||||
{
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
[JsonProperty("url")]
|
||||
public string Url { get; set; }
|
||||
[JsonProperty("content")]
|
||||
public int? Content { get; set; }
|
||||
[JsonProperty("media")]
|
||||
public int? Media { get; set; }
|
||||
[JsonProperty("openInNewWindow")]
|
||||
public bool OpenInNewWindow { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("contactDetails")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class ContactDetails
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonProperty("address")]
|
||||
public string Address { get; set; }
|
||||
[JsonProperty("telephone")]
|
||||
public string Telephone { get; set; }
|
||||
[JsonProperty("mobile")]
|
||||
public string Mobile { get; set; }
|
||||
[JsonProperty("fax")]
|
||||
public string Fax { get; set; }
|
||||
[JsonProperty("email")]
|
||||
public string Email { get; set; }
|
||||
[JsonProperty("webSite")]
|
||||
public UrlPicker WebSite { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("companyDetails")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class CompanyDetails
|
||||
{
|
||||
[JsonProperty("region")]
|
||||
public string Region { get; set; }
|
||||
[JsonProperty("contactDetails")]
|
||||
public ContactDetails ContactDetails { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("allContactDetails")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class AllContactDetails
|
||||
{
|
||||
public ContactDetails UserDetails { get; set; }
|
||||
public ContactDetails AdminDetails { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[AsArchetype("contactDetailsList")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class ContactDetailsList : List<ContactDetails>
|
||||
{
|
||||
}
|
||||
|
||||
[AsArchetype("annualStatement")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class AnnualStatement
|
||||
{
|
||||
public DateTime FiscalYearStart { get; set; }
|
||||
public DateTime FiscalYearEnd { get; set; }
|
||||
public DateTime? DividendPaymentDate { get; set; }
|
||||
public Int32 TotalShares { get; set; }
|
||||
public Double Sales { get; set; }
|
||||
public Decimal Profit { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("mergerDetails")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class MergerDetails
|
||||
{
|
||||
public DateTime MergerDate { get; set; }
|
||||
[JsonIgnore]
|
||||
public decimal MergerValue { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region complex nested model
|
||||
|
||||
[AsArchetype("pages")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class PageDetails
|
||||
{
|
||||
[JsonProperty("pages")]
|
||||
public string Pages { get; set; }
|
||||
[AsFieldset]
|
||||
[JsonProperty("captions")]
|
||||
public Captions Captions { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("captions")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class Captions
|
||||
{
|
||||
[JsonProperty("captions")]
|
||||
public TextList TextStringArray { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("textstringArray")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class TextList : List<TextItem>
|
||||
{
|
||||
}
|
||||
|
||||
[AsArchetype("textstringArray")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class TextItem
|
||||
{
|
||||
[JsonProperty("textstring")]
|
||||
public string TextString { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region complex nested tree model
|
||||
|
||||
public abstract class PageBase
|
||||
{
|
||||
public string PageTitle { get; set; }
|
||||
public string BodyText { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("slideShow")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class SlideShow
|
||||
{
|
||||
public string Slides { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("seo")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class Seo
|
||||
{
|
||||
public string MetaTitle { get; set; }
|
||||
public string MetaDescription { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("TextPage")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class TextPage : PageBase
|
||||
{
|
||||
[AsFieldset]
|
||||
public SlideShow Media { get; set; }
|
||||
|
||||
[AsFieldset]
|
||||
public Seo Seo { get; set; }
|
||||
}
|
||||
|
||||
[AsArchetype("TextPageList")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class TextPageList : List<TextPage>
|
||||
{
|
||||
}
|
||||
|
||||
[AsArchetype("Pages")]
|
||||
[JsonConverter(typeof(ArchetypeJsonConverter))]
|
||||
public class PageList
|
||||
{
|
||||
public TextPageList Pages { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
namespace Archetype.Tests.Serialization
|
||||
{
|
||||
public class JsonTestStrings
|
||||
{
|
||||
public const string _MERGER_DETAILS_JSON =
|
||||
@"{
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""mergerDetails"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""MergerDate"",
|
||||
""value"": ""07/06/2014 08:09:10""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
public const string _ANNUAL_STATEMENT_JSON =
|
||||
@"{
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""annualStatement"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""FiscalYearStart"",
|
||||
""value"": ""01/09/2013 00:00:00""
|
||||
},
|
||||
{
|
||||
""alias"": ""FiscalYearEnd"",
|
||||
""value"": ""31/08/2014 00:00:00""
|
||||
},
|
||||
{
|
||||
""alias"": ""DividendPaymentDate"",
|
||||
""value"": """"
|
||||
},
|
||||
{
|
||||
""alias"": ""TotalShares"",
|
||||
""value"": ""345678""
|
||||
},
|
||||
{
|
||||
""alias"": ""Sales"",
|
||||
""value"": ""123456700.89""
|
||||
},
|
||||
{
|
||||
""alias"": ""Profit"",
|
||||
""value"": ""1123456.78""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
public const string _CONTACT_DETAILS_JSON =
|
||||
@"{
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""contactDetails"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""name"",
|
||||
""value"": ""Test""
|
||||
},
|
||||
{
|
||||
""alias"": ""address"",
|
||||
""value"": ""Test Address""
|
||||
},
|
||||
{
|
||||
""alias"": ""telephone"",
|
||||
""value"": ""111""
|
||||
},
|
||||
{
|
||||
""alias"": ""mobile"",
|
||||
""value"": ""000""
|
||||
},
|
||||
{
|
||||
""alias"": ""fax"",
|
||||
""value"": ""000""
|
||||
},
|
||||
{
|
||||
""alias"": ""email"",
|
||||
""value"": ""test@test.com""
|
||||
},
|
||||
{
|
||||
""alias"": ""webSite"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""urlPicker"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""title"",
|
||||
""value"": ""The Test Company""
|
||||
},
|
||||
{
|
||||
""alias"": ""url"",
|
||||
""value"": ""http://test.com""
|
||||
},
|
||||
{
|
||||
""alias"": ""content"",
|
||||
""value"": """"
|
||||
},
|
||||
{
|
||||
""alias"": ""media"",
|
||||
""value"": """"
|
||||
},
|
||||
{
|
||||
""alias"": ""openInNewWindow"",
|
||||
""value"": ""1""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
public const string _COMPANY_DETAILS_JSON =
|
||||
@"{
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""companyDetails"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""region"",
|
||||
""value"": ""Test Region""
|
||||
},
|
||||
{
|
||||
""alias"": ""contactDetails"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""contactDetails"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""name"",
|
||||
""value"": ""Test""
|
||||
},
|
||||
{
|
||||
""alias"": ""address"",
|
||||
""value"": ""Test Address""
|
||||
},
|
||||
{
|
||||
""alias"": ""telephone"",
|
||||
""value"": ""111""
|
||||
},
|
||||
{
|
||||
""alias"": ""mobile"",
|
||||
""value"": ""000""
|
||||
},
|
||||
{
|
||||
""alias"": ""fax"",
|
||||
""value"": ""000""
|
||||
},
|
||||
{
|
||||
""alias"": ""email"",
|
||||
""value"": ""test@test.com""
|
||||
},
|
||||
{
|
||||
""alias"": ""webSite"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""urlPicker"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""title"",
|
||||
""value"": ""The Test Company""
|
||||
},
|
||||
{
|
||||
""alias"": ""url"",
|
||||
""value"": ""http://test.com""
|
||||
},
|
||||
{
|
||||
""alias"": ""content"",
|
||||
""value"": """"
|
||||
},
|
||||
{
|
||||
""alias"": ""media"",
|
||||
""value"": """"
|
||||
},
|
||||
{
|
||||
""alias"": ""openInNewWindow"",
|
||||
""value"": ""1""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
public const string _PAGE_DETAILS_JSON =
|
||||
@"{
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""pages"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""pages"",
|
||||
""value"": ""2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""alias"": ""captions"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""captions"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""textstringArray"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""textstring"",
|
||||
""value"": ""First Page""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""alias"": ""textstringArray"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""textstring"",
|
||||
""value"": ""Second Page""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""alias"": ""textstringArray"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""textstring"",
|
||||
""value"": ""Third Page""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""alias"": ""textstringArray"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""textstring"",
|
||||
""value"": ""Fourth Page""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
public const string _PAGES_JSON =
|
||||
@"{
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""Pages"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""Pages"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""TextPage"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""Media"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""slideShow"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""Slides"",
|
||||
""value"": ""1,2,3,4,5,6,7,8""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
""alias"": ""Seo"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""seo"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""MetaTitle"",
|
||||
""value"": ""Test Meta Title""
|
||||
},
|
||||
{
|
||||
""alias"": ""MetaDescription"",
|
||||
""value"": ""Test Meta Description""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
""alias"": ""PageTitle"",
|
||||
""value"": ""Home Page""
|
||||
},
|
||||
{
|
||||
""alias"": ""BodyText"",
|
||||
""value"": ""Home Page Body""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""alias"": ""TextPage"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""Media"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""slideShow"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""Slides"",
|
||||
""value"": ""1,2,3,4,5,6,7,8""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
""alias"": ""Seo"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""seo"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""MetaTitle"",
|
||||
""value"": ""Test Meta Title""
|
||||
},
|
||||
{
|
||||
""alias"": ""MetaDescription"",
|
||||
""value"": ""Test Meta Description""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
""alias"": ""PageTitle"",
|
||||
""value"": ""About us Page""
|
||||
},
|
||||
{
|
||||
""alias"": ""BodyText"",
|
||||
""value"": ""About us Page Body""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""alias"": ""TextPage"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""Media"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""slideShow"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""Slides"",
|
||||
""value"": ""1,2,3,4,5,6,7,8""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
""alias"": ""Seo"",
|
||||
""value"": {
|
||||
""fieldsets"": [
|
||||
{
|
||||
""alias"": ""seo"",
|
||||
""properties"": [
|
||||
{
|
||||
""alias"": ""MetaTitle"",
|
||||
""value"": ""Test Meta Title""
|
||||
},
|
||||
{
|
||||
""alias"": ""MetaDescription"",
|
||||
""value"": ""Test Meta Description""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
""alias"": ""PageTitle"",
|
||||
""value"": ""Contact us Page""
|
||||
},
|
||||
{
|
||||
""alias"": ""BodyText"",
|
||||
""value"": ""Contact us Page Body""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
public const string _NULL_VALUES_JSON = @"{""fieldsets"":[{""alias"":""contactDetails"",""properties"":[{""alias"":""name"",""value"":""""},{""alias"":""address"",""value"":""""},{""alias"":""telephone"",""value"":""""},{""alias"":""mobile"",""value"":""""},{""alias"":""fax"",""value"":""""},{""alias"":""email"",""value"":""""},{""alias"":""webSite"",""value"":""""}]}]}";
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
@@ -220,6 +220,10 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\VersionInfo.cs" />
|
||||
<Compile Include="PropertyConverters\ArchetypeValueConverter.cs" />
|
||||
<Compile Include="Serialization\AsArchetypeAttribute.cs" />
|
||||
<Compile Include="Serialization\ArchetypeJsonConverter.cs" />
|
||||
<Compile Include="Serialization\AsFieldsetAttribute.cs" />
|
||||
<Compile Include="Serialization\SerializationExtensions.cs" />
|
||||
<Compile Include="PropertyEditors\ArchetypePropertyEditor.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,6 +4,7 @@ using Archetype.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Archetype.Extensions
|
||||
{
|
||||
@@ -46,7 +47,7 @@ namespace Archetype.Extensions
|
||||
}
|
||||
}
|
||||
|
||||
internal Models.ArchetypeModel DeserializeJsonToArchetype(string sourceJson, int dataTypeId)
|
||||
internal Models.ArchetypeModel DeserializeJsonToArchetype(string sourceJson, int dataTypeId, PublishedContentType hostContentType = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -56,7 +57,7 @@ namespace Archetype.Extensions
|
||||
{
|
||||
// Get list of configured properties and their types and map them to the deserialized archetype model
|
||||
var preValue = GetArchetypePreValueFromDataTypeId(dataTypeId);
|
||||
RetrieveAdditionalProperties(ref archetype, preValue);
|
||||
RetrieveAdditionalProperties(ref archetype, preValue, hostContentType);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -110,7 +111,7 @@ namespace Archetype.Extensions
|
||||
/// </summary>
|
||||
/// <param name="archetype">The Archetype to add the additional metadata to</param>
|
||||
/// <param name="preValue">The configuration of the Archetype</param>
|
||||
private void RetrieveAdditionalProperties(ref Models.ArchetypeModel archetype, ArchetypePreValue preValue)
|
||||
private void RetrieveAdditionalProperties(ref Models.ArchetypeModel archetype, ArchetypePreValue preValue, PublishedContentType hostContentType = null)
|
||||
{
|
||||
foreach (var fieldset in preValue.Fieldsets)
|
||||
{
|
||||
@@ -125,6 +126,7 @@ namespace Archetype.Extensions
|
||||
propertyInst.DataTypeGuid = property.DataTypeGuid.ToString();
|
||||
propertyInst.DataTypeId = GetDataTypeByGuid(property.DataTypeGuid).Id;
|
||||
propertyInst.PropertyEditorAlias = property.PropertyEditorAlias;
|
||||
propertyInst.HostContentType = hostContentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Mvc.Html;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web;
|
||||
using Archetype.Models;
|
||||
|
||||
@@ -23,5 +26,59 @@ namespace Archetype.Extensions
|
||||
{
|
||||
return prop.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditorAlias);
|
||||
}
|
||||
|
||||
public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel)
|
||||
{
|
||||
return RenderPartials(htmlHelper, archetypeModel, null, null);
|
||||
}
|
||||
|
||||
public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath)
|
||||
{
|
||||
return RenderPartials(htmlHelper, archetypeModel, partialPath, null);
|
||||
}
|
||||
|
||||
public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, ViewDataDictionary viewDataDictionary)
|
||||
{
|
||||
return RenderPartials(htmlHelper, archetypeModel, null, viewDataDictionary);
|
||||
}
|
||||
|
||||
public static IHtmlString RenderArchetypePartials(this HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath, ViewDataDictionary viewDataDictionary)
|
||||
{
|
||||
return RenderPartials(htmlHelper, archetypeModel, partialPath, viewDataDictionary);
|
||||
}
|
||||
|
||||
private static IHtmlString RenderPartials(HtmlHelper htmlHelper, ArchetypeModel archetypeModel, string partialPath, ViewDataDictionary viewDataDictionary)
|
||||
{
|
||||
var context = HttpContext.Current;
|
||||
|
||||
if (archetypeModel == null || context == null)
|
||||
{
|
||||
return new HtmlString("");
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
var pathToPartials = "~/Views/Partials/Archetype/";
|
||||
if (!string.IsNullOrEmpty(partialPath))
|
||||
{
|
||||
pathToPartials = partialPath;
|
||||
}
|
||||
|
||||
foreach (var fieldsetModel in archetypeModel)
|
||||
{
|
||||
var partial = pathToPartials + fieldsetModel.Alias + ".cshtml";
|
||||
|
||||
if (System.IO.File.Exists(context.Server.MapPath(partial)))
|
||||
{
|
||||
sb.AppendLine(htmlHelper.Partial(partial, fieldsetModel, viewDataDictionary).ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Info<ArchetypeModel>(string.Format("The partial for {0} could not be found. Please create a partial with that name or rename your alias.", context.Server.MapPath(partial)));
|
||||
}
|
||||
}
|
||||
|
||||
return new HtmlString(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Archetype.Models
|
||||
{
|
||||
var property = GetProperty(propertyAlias);
|
||||
|
||||
if (property == null || string.IsNullOrEmpty(property.Value.ToString()))
|
||||
if (property == null || property.Value == null || string.IsNullOrEmpty(property.Value.ToString()))
|
||||
return default(T);
|
||||
|
||||
return property.GetValue<T>();
|
||||
@@ -43,7 +43,7 @@ namespace Archetype.Models
|
||||
public bool HasValue(string propertyAlias)
|
||||
{
|
||||
var property = GetProperty(propertyAlias);
|
||||
if (property == null)
|
||||
if (property == null || property.Value == null)
|
||||
return false;
|
||||
|
||||
return !string.IsNullOrEmpty(property.Value.ToString());
|
||||
@@ -57,4 +57,4 @@ namespace Archetype.Models
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace Archetype.Models
|
||||
internal string SerializeForPersistence()
|
||||
{
|
||||
var json = JObject.Parse(JsonConvert.SerializeObject(this));
|
||||
var propertiesToRemove = new String[] { "propertyEditorAlias", "dataTypeId", "dataTypeGuid" };
|
||||
var propertiesToRemove = new String[] { "propertyEditorAlias", "dataTypeId", "dataTypeGuid", "hostContentType" };
|
||||
|
||||
json.Descendants().OfType<JProperty>()
|
||||
.Where(p => propertiesToRemove.Contains(p.Name))
|
||||
|
||||
@@ -33,6 +33,6 @@ namespace Archetype.Models
|
||||
public bool Required { get; set; }
|
||||
|
||||
[JsonProperty("regEx")]
|
||||
public bool RegEx { get; set; }
|
||||
public string RegEx { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,9 @@ namespace Archetype.Models
|
||||
[JsonProperty("dataTypeGuid")]
|
||||
internal string DataTypeGuid { get; set; }
|
||||
|
||||
[JsonProperty("hostContentType")]
|
||||
internal PublishedContentType HostContentType { get; set; }
|
||||
|
||||
public T GetValue<T>()
|
||||
{
|
||||
|
||||
@@ -80,7 +83,7 @@ namespace Archetype.Models
|
||||
|
||||
private PublishedPropertyType CreateDummyPropertyType(int dataTypeId, string propertyEditorAlias)
|
||||
{
|
||||
return new PublishedPropertyType(null,
|
||||
return new PublishedPropertyType(this.HostContentType,
|
||||
new PropertyType(new DataTypeDefinition(-1, propertyEditorAlias)
|
||||
{
|
||||
Id = dataTypeId
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("1.0")]
|
||||
[assembly: AssemblyFileVersion("1.0-beta")]
|
||||
[assembly: AssemblyVersion("1.2")]
|
||||
[assembly: AssemblyFileVersion("1.2-beta")]
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace Archetype.PropertyConverters
|
||||
return defaultValue;
|
||||
|
||||
var archetype = new ArchetypeHelper().DeserializeJsonToArchetype(source.ToString(),
|
||||
(propertyType != null ? propertyType.DataTypeId : -1));
|
||||
(propertyType != null ? propertyType.DataTypeId : -1),
|
||||
(propertyType != null ? propertyType.ContentType : null));
|
||||
|
||||
return archetype;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ using Umbraco.Core.Logging;
|
||||
namespace Archetype.PropertyEditors
|
||||
{
|
||||
[PropertyEditorAsset(ClientDependencyType.Javascript, "/App_Plugins/Archetype/js/archetype.js")]
|
||||
[PropertyEditor("Imulus.Archetype", "Archetype", "/App_Plugins/Archetype/views/archetype.html",
|
||||
ValueType = "JSON")]
|
||||
[PropertyEditor("Imulus.Archetype", "Archetype", "/App_Plugins/Archetype/views/archetype.html", ValueType = "JSON")]
|
||||
public class ArchetypePropertyEditor : PropertyEditor
|
||||
{
|
||||
#region Pre Value Editor
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Archetype.Serialization
|
||||
{
|
||||
public class ArchetypeJsonConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var models = GenerateModels(value);
|
||||
|
||||
if (models.Count < 1)
|
||||
return;
|
||||
|
||||
if (models.Count == 1 && models[0] == null)
|
||||
return;
|
||||
|
||||
var jObj = new JObject
|
||||
{
|
||||
{
|
||||
"fieldsets",
|
||||
new JArray( new JRaw(SerializeModels(models)))
|
||||
}
|
||||
};
|
||||
|
||||
writer.WriteRaw(ApplyFormatting(jObj.ToString(), writer.Formatting));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jToken = JToken.ReadFrom(reader);
|
||||
|
||||
if (jToken == null)
|
||||
return null;
|
||||
|
||||
var obj = Activator.CreateInstance(objectType);
|
||||
|
||||
if (null != obj as IEnumerable<object>
|
||||
&& jToken["fieldsets"] != null && jToken["fieldsets"].Any())
|
||||
{
|
||||
return DeserializeEnumerableObject(obj, jToken);
|
||||
}
|
||||
|
||||
return null == jToken as JArray
|
||||
? DeserializeObject(obj, jToken)
|
||||
: PopulateProperties(obj, jToken);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return IsValueArchetypeDatatype(objectType);
|
||||
}
|
||||
|
||||
#region private methods
|
||||
|
||||
private string ApplyFormatting(string json, Formatting formatting)
|
||||
{
|
||||
return JToken.Parse(json).ToString(formatting);
|
||||
}
|
||||
|
||||
private IList GenerateModels(object value)
|
||||
{
|
||||
var models = value as IList;
|
||||
|
||||
if (null != models)
|
||||
return models;
|
||||
|
||||
var properties = GetSerialiazableProperties(value).ToList();
|
||||
|
||||
if (!PropertyLayoutHasFieldsets(properties))
|
||||
return new List<object>() { value };
|
||||
|
||||
var dynamicModel = new ExpandoObject() as IDictionary<string, object>;
|
||||
|
||||
foreach (var pInfo in properties.Where(pInfo => !HasAsFieldsetAttribute(pInfo)))
|
||||
{
|
||||
dynamicModel.Add(GetJsonPropertyName(pInfo), pInfo.GetValue(value));
|
||||
}
|
||||
|
||||
var fieldsetModels = properties.Where(HasAsFieldsetAttribute)
|
||||
.Select(pInfo => pInfo.GetValue(value));
|
||||
|
||||
models = new List<object>
|
||||
{
|
||||
dynamicModel,
|
||||
};
|
||||
|
||||
models = ((IEnumerable<object>)models).Concat(fieldsetModels).ToList();
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
private object DeserializeEnumerableObject(object obj, JToken jToken)
|
||||
{
|
||||
var model = obj as IEnumerable<object>;
|
||||
|
||||
var itemType = model.GetType().BaseType.GetGenericArguments().First();
|
||||
foreach (var fs in jToken["fieldsets"].Where(fs => fs["alias"].ToString().Equals(GetFieldsetName(itemType))))
|
||||
{
|
||||
var item = JsonConvert.DeserializeObject(
|
||||
fs["properties"].ToString(), itemType, GetArchetypeDatatypeConverter());
|
||||
|
||||
obj.GetType().GetMethod("Add").Invoke(obj, new[] { item });
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private object DeserializeObject(object obj, JToken jToken)
|
||||
{
|
||||
var properties = GetSerialiazableProperties(obj).ToList();
|
||||
var asFieldset = properties.Where(HasAsFieldsetAttribute).ToList();
|
||||
|
||||
foreach (var propInfo in asFieldset)
|
||||
{
|
||||
var propAlias = GetJsonPropertyName(propInfo);
|
||||
var fsJToken = GetFieldsetProperties(propInfo.PropertyType, jToken);
|
||||
var propJToken =
|
||||
fsJToken.Single(p => p.SelectToken("alias").ToString().Equals(propAlias));
|
||||
|
||||
if (propJToken == null)
|
||||
continue;
|
||||
|
||||
var propValue = IsValueArchetypeDatatype(propInfo.PropertyType)
|
||||
? JsonConvert.DeserializeObject(fsJToken.ToString(), propInfo.PropertyType,
|
||||
GetArchetypeDatatypeConverter())
|
||||
: GetDeserializedPropertyValue(fsJToken, propInfo.PropertyType); ;
|
||||
|
||||
propInfo.SetValue(obj, propValue);
|
||||
}
|
||||
|
||||
return PopulateProperties(obj, GetFieldsetProperties(obj.GetType(), jToken));
|
||||
}
|
||||
|
||||
private JToken GetFieldsetProperties(Type objType, JToken jToken)
|
||||
{
|
||||
var objAlias = GetFieldsetName(objType);
|
||||
return
|
||||
jToken["fieldsets"].Single(p => p.SelectToken("alias").ToString().Equals(objAlias)).SelectToken("properties");
|
||||
}
|
||||
|
||||
private object PopulateProperties(object obj, JToken jToken)
|
||||
{
|
||||
var properties = GetSerialiazableProperties(obj);
|
||||
|
||||
foreach (var propertyInfo in properties)
|
||||
{
|
||||
var propAlias = GetJsonPropertyName(propertyInfo);
|
||||
|
||||
var propJToken = jToken.SingleOrDefault(p => p.SelectToken("alias").ToString().Equals(propAlias));
|
||||
|
||||
if (propJToken == null)
|
||||
continue;
|
||||
|
||||
var propValue = GetPropertyValue(propertyInfo, propJToken);
|
||||
|
||||
propertyInfo.SetValue(obj, propValue);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private object GetPropertyValue(PropertyInfo propertyInfo, JToken propJToken)
|
||||
{
|
||||
return IsValueArchetypeDatatype(propertyInfo.PropertyType)
|
||||
? JsonConvert.DeserializeObject(propJToken["value"].ToString(), propertyInfo.PropertyType,
|
||||
GetArchetypeDatatypeConverter())
|
||||
: GetDeserializedPropertyValue(propJToken["value"], propertyInfo.PropertyType);
|
||||
}
|
||||
|
||||
private bool PropertyLayoutHasFieldsets(IEnumerable<PropertyInfo> properties)
|
||||
{
|
||||
return properties.Any(HasAsFieldsetAttribute);
|
||||
}
|
||||
|
||||
private static bool HasAsFieldsetAttribute(PropertyInfo pInfo)
|
||||
{
|
||||
return pInfo
|
||||
.GetCustomAttributes(typeof(AsFieldsetAttribute), true).Length > 0;
|
||||
}
|
||||
|
||||
private IEnumerable SerializeModels(IEnumerable models)
|
||||
{
|
||||
var fieldsetJson = (from object model in models where null != model select SerializeModel(model)).ToList();
|
||||
|
||||
return String.Join(",", fieldsetJson);
|
||||
}
|
||||
|
||||
private string SerializeModel(object value)
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
var jObj = IsExpandoObject(value)
|
||||
? GetJObjectFromExpandoObject(value as IDictionary<string, object>)
|
||||
: GetJObject(value);
|
||||
|
||||
var fieldsetJson = new StringBuilder();
|
||||
var fieldsetWriter = new StringWriter(fieldsetJson);
|
||||
|
||||
using (var jsonWriter = new JsonTextWriter(fieldsetWriter))
|
||||
{
|
||||
jObj.WriteTo(jsonWriter);
|
||||
}
|
||||
|
||||
return fieldsetJson.ToString();
|
||||
}
|
||||
|
||||
private bool IsExpandoObject(object value)
|
||||
{
|
||||
return value.GetType().Name.Equals(typeof (ExpandoObject).Name);
|
||||
}
|
||||
|
||||
private JObject GetJObjectFromExpandoObject(IEnumerable<KeyValuePair<string, object>> obj)
|
||||
{
|
||||
var property = obj.ElementAt(0);
|
||||
var alias = property.Key;
|
||||
var value = property.Value;
|
||||
|
||||
var jObj = new JObject
|
||||
{
|
||||
{
|
||||
"alias",
|
||||
new JValue(alias)
|
||||
}
|
||||
};
|
||||
|
||||
var fsProperties = new List<JObject>
|
||||
{
|
||||
new JObject {new JProperty("alias", alias), new JProperty("value", value)}
|
||||
};
|
||||
jObj.Add("properties", new JRaw(JsonConvert.SerializeObject(fsProperties)));
|
||||
|
||||
return jObj;
|
||||
}
|
||||
|
||||
private JObject GetJObject(object obj)
|
||||
{
|
||||
var jObj = new JObject
|
||||
{
|
||||
{
|
||||
"alias",
|
||||
new JValue(GetFieldsetName(obj.GetType()))
|
||||
}
|
||||
};
|
||||
|
||||
var properties = GetSerialiazableProperties(obj);
|
||||
|
||||
var fsProperties = new List<JObject>();
|
||||
|
||||
foreach (var propertyInfo in properties)
|
||||
{
|
||||
var fsProperty = new JObject();
|
||||
var jProperty = new JProperty("alias", GetJsonPropertyName(propertyInfo));
|
||||
fsProperty.Add(jProperty);
|
||||
|
||||
var propValue = propertyInfo.GetValue(obj, null);
|
||||
|
||||
fsProperty.Add(
|
||||
new JProperty("value",
|
||||
IsValueArchetypeDatatype(propValue)
|
||||
? new JRaw(JsonConvert.SerializeObject(propValue,
|
||||
GetArchetypeDatatypeConverter()))
|
||||
: new JValue(GetSerializedPropertyValue(propValue))));
|
||||
|
||||
fsProperties.Add(fsProperty);
|
||||
}
|
||||
|
||||
jObj.Add("properties", new JRaw(JsonConvert.SerializeObject(fsProperties)));
|
||||
|
||||
return jObj;
|
||||
}
|
||||
|
||||
private IEnumerable<PropertyInfo> GetSerialiazableProperties(object obj)
|
||||
{
|
||||
return obj.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(prop => !Attribute.IsDefined(prop, typeof(JsonIgnoreAttribute)));
|
||||
}
|
||||
|
||||
private string GetJsonPropertyName(PropertyInfo property)
|
||||
{
|
||||
var attributes = property.GetCustomAttributes(true);
|
||||
var jsonPropAttribute = (JsonPropertyAttribute)attributes.FirstOrDefault(attr => attr is JsonPropertyAttribute);
|
||||
|
||||
return jsonPropAttribute != null ? jsonPropAttribute.PropertyName : property.Name;
|
||||
}
|
||||
|
||||
private string GetFieldsetName(Type type)
|
||||
{
|
||||
var attributes = type.GetCustomAttributes(true);
|
||||
var archetypeDatatypeAttribute = (AsArchetypeAttribute)attributes.FirstOrDefault(attr => attr is AsArchetypeAttribute);
|
||||
|
||||
return archetypeDatatypeAttribute != null ? archetypeDatatypeAttribute.FieldsetName : type.Name;
|
||||
}
|
||||
|
||||
private bool IsValueArchetypeDatatype(object value)
|
||||
{
|
||||
return value != null &&
|
||||
IsValueArchetypeDatatype(value.GetType());
|
||||
}
|
||||
|
||||
private bool IsValueArchetypeDatatype(Type type)
|
||||
{
|
||||
return type.GetCustomAttributes(typeof(AsArchetypeAttribute), true).Length > 0;
|
||||
}
|
||||
|
||||
private JsonConverter GetArchetypeDatatypeConverter()
|
||||
{
|
||||
return (JsonConverter)Activator.CreateInstance(GetType());
|
||||
}
|
||||
|
||||
private string GetSerializedPropertyValue(object propValue)
|
||||
{
|
||||
if (propValue == null)
|
||||
return String.Empty;
|
||||
|
||||
if (propValue is bool)
|
||||
return (bool)propValue ? GetSerializedPropertyValue(1) : GetSerializedPropertyValue(0);
|
||||
|
||||
return String.Format("{0}", propValue);
|
||||
}
|
||||
|
||||
private object GetDeserializedPropertyValue(JToken jToken, Type type)
|
||||
{
|
||||
if (String.IsNullOrEmpty(jToken.ToString()))
|
||||
return GetDefault(type);
|
||||
|
||||
var localType = Nullable.GetUnderlyingType(type) ?? type;
|
||||
|
||||
if (localType == typeof(bool))
|
||||
return jToken.ToString() == "1";
|
||||
|
||||
return localType == typeof(DateTime)
|
||||
? Convert.ToDateTime(jToken.ToString())
|
||||
: jToken.ToObject(localType);
|
||||
}
|
||||
|
||||
private object GetDefault(Type type)
|
||||
{
|
||||
return type.IsValueType ? Activator.CreateInstance(type) : null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Archetype.Serialization
|
||||
{
|
||||
public class AsArchetypeAttribute : Attribute
|
||||
{
|
||||
public string FieldsetName { get; set; }
|
||||
|
||||
public AsArchetypeAttribute(string fieldsetname)
|
||||
{
|
||||
FieldsetName = fieldsetname;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Archetype.Serialization
|
||||
{
|
||||
public class AsFieldsetAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web;
|
||||
|
||||
namespace Archetype.Serialization
|
||||
{
|
||||
public static class SerializationExtensions
|
||||
{
|
||||
//temporary
|
||||
public static string GetPropertyDataValue(this IPublishedContent contentPage, string propertyAlias)
|
||||
{
|
||||
if (contentPage == null || !contentPage.HasProperty(propertyAlias))
|
||||
return null;
|
||||
|
||||
return (string)contentPage.Properties.Single(p => p.PropertyTypeAlias == propertyAlias).DataValue;
|
||||
}
|
||||
|
||||
public static T GetModelFromArchetype<T>(this IPublishedContent content,
|
||||
string cmsFieldAlias, bool returnInstanceIfNull = false)
|
||||
where T : class, new()
|
||||
{
|
||||
var archetypeJson = content.GetPropertyDataValue(cmsFieldAlias);
|
||||
return JsonConvert.DeserializeObject<T>(archetypeJson) ??
|
||||
(returnInstanceIfNull ? Activator.CreateInstance<T>() : default(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
angular.module("umbraco.directives").directive('archetypeCustomView', function ($compile, $http) {
|
||||
var linker = function (scope, element, attrs) {
|
||||
|
||||
var config = scope.archetype.config.archetypeConfig;
|
||||
|
||||
var view = "/App_plugins/Archetype/views/archetype.default.html";
|
||||
if(config.customViewPath) {
|
||||
view = config.customViewPath;
|
||||
}
|
||||
|
||||
$http.get(view).then(function(data) {
|
||||
|
||||
scope.model = {};
|
||||
scope.model.value = scope.archetype.value;
|
||||
scope.model.config = scope.archetype.config;
|
||||
|
||||
element.html(data.data).show();
|
||||
|
||||
$compile(element.contents())(scope);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "A",
|
||||
replace: true,
|
||||
link: linker,
|
||||
scope: {
|
||||
archetype: "="
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("umbraco.directives").directive('archetypeProperty', function ($compile, $http, archetypePropertyEditorResource, umbPropEditorHelper, $timeout, $rootScope, $q) {
|
||||
|
||||
|
||||
function getFieldsetByAlias(fieldsets, alias)
|
||||
{
|
||||
return _.find(fieldsets, function(fieldset){
|
||||
@@ -56,6 +56,10 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
|
||||
var alias = configFieldsetModel.properties[scope.propertyConfigIndex].alias;
|
||||
var defaultValue = configFieldsetModel.properties[scope.propertyConfigIndex].value;
|
||||
var umbracoPropertyAlias = scope.umbracoPropertyAlias;
|
||||
// initialize container for invalid fieldset property identifiers (store on ngModelCtrl to separate Archetype validations, e.g. when there two Archetype properties on the same document)
|
||||
if(ngModelCtrl.invalidProperties == null) {
|
||||
ngModelCtrl.invalidProperties = [];
|
||||
}
|
||||
|
||||
//try to convert the defaultValue to a JS object
|
||||
defaultValue = jsonOrString(defaultValue, scope.archetypeConfig.developerMode, "defaultValue");
|
||||
@@ -81,48 +85,77 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
|
||||
|
||||
var mergedConfig = _.extend(defaultConfigObj, config);
|
||||
|
||||
loadView(pathToView, mergedConfig, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl);
|
||||
loadView(pathToView, mergedConfig, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl, validateProperty);
|
||||
});
|
||||
});
|
||||
|
||||
ngModelCtrl.$parsers.push(validate);
|
||||
ngModelCtrl.$formatters.push(validate);
|
||||
|
||||
function validate(renderModel){
|
||||
var valid = true;
|
||||
|
||||
_.each(renderModel, function(fieldset){
|
||||
fieldset.isValid = true;
|
||||
_.each(fieldset.properties, function(property){
|
||||
property.isValid = true;
|
||||
|
||||
var propertyConfig = getPropertyByAlias(configFieldsetModel, property.alias);
|
||||
if (propertyConfig) {
|
||||
if(propertyConfig.required && (property.value == null || property.value === "")) {
|
||||
fieldset.isValid = false;
|
||||
property.isValid = false;
|
||||
valid = false;
|
||||
}
|
||||
// issue 116: RegEx validate property value
|
||||
// Only validate the property value if anything has been entered - RegEx is considered a supplement to "required".
|
||||
if (valid == true && propertyConfig.regEx && property.value) {
|
||||
var regEx = new RegExp(propertyConfig.regEx);
|
||||
if (regEx.test(property.value) == false) {
|
||||
fieldset.isValid = false;
|
||||
property.isValid = false;
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
scope.$on("formSubmitting", function (ev, args) {
|
||||
// "hard" validate to highlight any erroneous entries
|
||||
_.each(scope.fieldset.properties, function (property) {
|
||||
validateProperty(scope.fieldset, property, true);
|
||||
});
|
||||
});
|
||||
|
||||
ngModelCtrl.$setValidity('validation', valid);
|
||||
return renderModel;
|
||||
scope.$on("formSubmitted", function (ev, args) {
|
||||
// reset the nested fieldset validation state after submit
|
||||
ngModelCtrl.invalidProperties = [];
|
||||
});
|
||||
|
||||
// need to pass the property fieldset here to clear any invalid state of the fieldset when validating a single fieldset property
|
||||
// - it's the Umbraco way to hide the invalid state when altering an invalid property, even if the new value isn't valid either
|
||||
function validateProperty(fieldset, property, markAsInvalid) {
|
||||
var valid = true;
|
||||
fieldset.isValid = true;
|
||||
property.isValid = true;
|
||||
var propertyConfig = getPropertyByAlias(configFieldsetModel, property.alias);
|
||||
if (propertyConfig) {
|
||||
// use property.value !== property.value to check for NaN values on numeric inputs
|
||||
if (propertyConfig.required && (property.value == null || property.value === "" || property.value !== property.value)) {
|
||||
valid = false;
|
||||
}
|
||||
// issue 116: RegEx validate property value
|
||||
// Only validate the property value if anything has been entered - RegEx is considered a supplement to "required".
|
||||
if (valid == true && propertyConfig.regEx && property.value) {
|
||||
var regEx = new RegExp(propertyConfig.regEx);
|
||||
if (regEx.test(property.value) == false) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
// only mark the property as invalid when doing a "hard" validation
|
||||
if (valid == false && markAsInvalid == true) {
|
||||
property.isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// handle nested fieldset validation by storing the identifier of all invalid fieldset properties
|
||||
var fieldsetIdentifier = scope.umbracoPropertyAlias + "_" + scope.fieldsetIndex;
|
||||
var propertyIdentifier = fieldsetIdentifier + "_" + property.alias;
|
||||
var propertyIdentifierIndex = ngModelCtrl.invalidProperties.indexOf(propertyIdentifier);
|
||||
if (valid == false) {
|
||||
if (propertyIdentifierIndex == -1) {
|
||||
ngModelCtrl.invalidProperties.push(propertyIdentifier);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (propertyIdentifierIndex != -1) {
|
||||
ngModelCtrl.invalidProperties.splice(propertyIdentifierIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (markAsInvalid) {
|
||||
// mark the entire fieldset as invalid if there are any invalid properties in the fieldset, otherwise mark it as valid
|
||||
fieldset.isValid =
|
||||
_.find(ngModelCtrl.invalidProperties, function (item) {
|
||||
return item.indexOf(fieldsetIdentifier) == 0
|
||||
}) == null;
|
||||
}
|
||||
|
||||
// set invalid state if one or more fieldsets contain invalid properties
|
||||
ngModelCtrl.$setValidity('validation', ngModelCtrl.invalidProperties.length == 0);
|
||||
}
|
||||
}
|
||||
|
||||
function loadView(view, config, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl) {
|
||||
function loadView(view, config, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl, validateProperty) {
|
||||
if (view)
|
||||
{
|
||||
$http.get(view).success(function (data) {
|
||||
@@ -157,11 +190,9 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
|
||||
scope.$watch('model.value', function (newValue, oldValue) {
|
||||
scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties[renderModelPropertyIndex].value = newValue;
|
||||
|
||||
// don't set the current value twice - this will keep Umbraco from prompting to discard changes immediately after saving
|
||||
if (newValue != oldValue) {
|
||||
//trigger the validation pipeline
|
||||
ngModelCtrl.$setViewValue(ngModelCtrl.$viewValue);
|
||||
}
|
||||
// call validation method for the property when the value changes
|
||||
// use "soft" validation to mimic the default umbraco validation style (show error highlights on submit, not while entering data)
|
||||
validateProperty(scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex], scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties[renderModelPropertyIndex], false);
|
||||
});
|
||||
|
||||
element.html(data).show();
|
||||
@@ -171,7 +202,7 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
|
||||
var def = $q.defer();
|
||||
def.resolve(true);
|
||||
$rootScope.$apply();
|
||||
}, 500)
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -180,7 +211,7 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
|
||||
return {
|
||||
require: "^ngModel",
|
||||
restrict: "E",
|
||||
rep1ace: true,
|
||||
replace: true,
|
||||
link: linker,
|
||||
scope: {
|
||||
property: '=',
|
||||
|
||||
@@ -125,6 +125,10 @@
|
||||
<label for="archetypeAdvancedOptionsCustomJs"><archetype-localize key="jsFile">JS File</archetype-localize><small><archetype-localize key="jsFileDescription">(Optional) Enter a path for a custom JS file to be included on the page.</archetype-localize></small></label>
|
||||
<input type="text" id="archetypeAdvancedOptionsCustomJs" ng-model="archetypeConfigRenderModel.customJsPath"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsCustomView"><archetype-localize key="viewFile">View File</archetype-localize><small><archetype-localize key="viewFileDescription">(Optional) Enter a path for a custom view file to be used to render this Archetype.</archetype-localize></small></label>
|
||||
<input type="text" id="archetypeAdvancedOptionsCustomView" ng-model="archetypeConfigRenderModel.customViewPath"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsDeveloperMode"><archetype-localize key="toggleDeveloperMode">Toggle Developer Mode</archetype-localize><small><archetype-localize key="toggleDeveloperModeDescription">Toggle Developer Mode</archetype-localize></small></label>
|
||||
<input type="checkbox" id="archetypeAdvancedOptionsDeveloperMode" ng-model="archetypeConfigRenderModel.developerMode"/>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<div class="archetypeEditor ng-class:model.config.customCssClass" ng-controller="Imulus.ArchetypeController">
|
||||
<textarea class="archetypeDeveloperModel" ng-show="model.config.developerMode" ng-model="model.value"></textarea>
|
||||
<ul ui-sortable="sortableOptions" ng-model="model.value.fieldsets" ng-show="!showAddButton()">
|
||||
<li ng-repeat="fieldset in model.value.fieldsets">
|
||||
<fieldset ng-class="[fieldset.alias, (!fieldset.isValid ? 'archetypeFieldsetError' : '')]" ng-init="fieldsetConfigModel = getConfigFieldsetByAlias(fieldset.alias)">
|
||||
<div class="archetypeFieldsetLabel" ng-class="{enableCollapsing: model.config.enableCollapsing}">
|
||||
<div ng-click="focusFieldset(fieldset)" class="label-sub module-label">
|
||||
<span class="caret" ng-hide="fieldset.collapse || !model.config.enableCollapsing"></span>
|
||||
<span class="caret caret-right" ng-show="fieldset.collapse && model.config.enableCollapsing"></span>
|
||||
<label>
|
||||
<i class="fieldsetIcon icon ng-class:fieldsetConfigModel.icon"></i>
|
||||
<span ng-bind="getFieldsetTitle(fieldsetConfigModel, $index)"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="archetypeEditorControls label-sub" ng-hide="model.config.hideFieldsetControls">
|
||||
<i class="icon icon-add dropdown-toggle" ng-show="canAdd()" data-toggle="{{ model.config.fieldsets.length > 1 ? 'dropdown' : ''}}" ng-click="model.config.fieldsets.length == 1 ? addRow(fieldset.alias, $index) : return"></i>
|
||||
<ul class="dropdown-menu umb-actions">
|
||||
<li ng-repeat="fieldsetModel in model.config.fieldsets" ng-click="addRow(fieldsetModel.alias, $parent.$index)">
|
||||
<a>
|
||||
<i class="fieldsetIcon icon ng-class:fieldsetModel.icon"></i>
|
||||
<span class="menu-label">{{fieldsetModel.label}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<i class="icon icon-remove" ng-click="removeRow($index)" ng-show="canRemove()"></i>
|
||||
<i class="icon icon-navigation handle" ng-show="canSort()"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="archetypeCollapser animate-hide" ng-hide="isCollapsed(fieldset)">
|
||||
<form class="form-inline">
|
||||
<div ng-class="[property.alias, (getPropertyValidity($parent.$index, property.alias) === false ? 'archetypePropertyError' : '')]" class="archetypeProperty control-group" ng-repeat="property in fieldsetConfigModel.properties">
|
||||
<label ng-hide="archetypeConfig.hidePropertyLabels == '1'" class="control-label" for="archetype-property-{{model.alias}}-{{$parent.$index}}-{{$index}}">
|
||||
<span>{{property.label}}</span>
|
||||
<div class="archetypeFieldsetHelpText" ng-show="property.helpText">
|
||||
<small>{{property.helpText}}</small>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<div class="controls">
|
||||
<archetype-property class="archetypeEditor" property="property" fieldset-index="$parent.$index" fieldset="fieldset" archetype-config="model.config" property-config-index="$index" archetype-render-model="model.value" umbraco-property-alias="model.alias" umbraco-form = "form"></archetype-property>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</fieldset>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-show="showAddButton()">
|
||||
<a data-toggle="{{ model.config.fieldsets.length > 1 ? 'dropdown' : ''}}" ng-click="model.config.fieldsets.length == 1 ? addRow(model.config.fieldsets[0].alias, 0) : return" prevent-default>
|
||||
<i class="icon icon-add dropdown-toggle"></i>
|
||||
<localize key="general_add" class="archetypeAddButtonText">Add</localize>
|
||||
</a>
|
||||
<ul class="dropdown-menu umb-actions">
|
||||
<li ng-repeat="fieldsetModel in model.config.fieldsets" ng-click="addRow(fieldsetModel.alias, 0)">
|
||||
<a>
|
||||
<i class="fieldsetIcon icon ng-class:fieldsetModel.icon"></i>
|
||||
<span class="menu-label">{{fieldsetModel.label}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,62 +1 @@
|
||||
<div class="archetypeEditor ng-class:model.config.customCssClass" ng-controller="Imulus.ArchetypeController">
|
||||
<textarea class="archetypeDeveloperModel" ng-show="model.config.developerMode" ng-model="model.value"></textarea>
|
||||
<ul ui-sortable="sortableOptions" ng-model="model.value.fieldsets" ng-show="!showAddButton()">
|
||||
<li ng-repeat="fieldset in model.value.fieldsets">
|
||||
<fieldset ng-class="{archetypeFieldsetError: !fieldset.isValid}" ng-init="fieldsetConfigModel = getConfigFieldsetByAlias(fieldset.alias)">
|
||||
<div class="archetypeFieldsetLabel" ng-class="{enableCollapsing: model.config.enableCollapsing}">
|
||||
<div ng-click="focusFieldset(fieldset)" class="label-sub module-label">
|
||||
<span class="caret" ng-hide="fieldset.collapse || !model.config.enableCollapsing"></span>
|
||||
<span class="caret caret-right" ng-show="fieldset.collapse && model.config.enableCollapsing"></span>
|
||||
<label>
|
||||
<i class="fieldsetIcon icon ng-class:fieldsetConfigModel.icon"></i>
|
||||
<span ng-bind="getFieldsetTitle(fieldsetConfigModel, $index)"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="archetypeEditorControls label-sub" ng-hide="model.config.hideFieldsetControls">
|
||||
<i class="icon icon-add dropdown-toggle" ng-show="canAdd()" data-toggle="{{ model.config.fieldsets.length > 1 ? 'dropdown' : ''}}" ng-click="model.config.fieldsets.length == 1 ? addRow(fieldset.alias, $index) : return"></i>
|
||||
<ul class="dropdown-menu umb-actions">
|
||||
<li ng-repeat="fieldsetModel in model.config.fieldsets" ng-click="addRow(fieldsetModel.alias, $parent.$index)">
|
||||
<a>
|
||||
<i class="fieldsetIcon icon ng-class:fieldsetModel.icon"></i>
|
||||
<span class="menu-label">{{fieldsetModel.label}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<i class="icon icon-remove" ng-click="removeRow($index)" ng-show="canRemove()"></i>
|
||||
<i class="icon icon-navigation handle" ng-show="canSort()"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="archetypeCollapser animate-hide" ng-hide="isCollapsed(fieldset)">
|
||||
<form class="form-inline">
|
||||
<div ng-class="{archetypePropertyError: getPropertyValidity($parent.$index, property.alias) === false}" class="archetypeProperty control-group" ng-repeat="property in fieldsetConfigModel.properties">
|
||||
<label ng-hide="archetypeConfig.hidePropertyLabels == '1'" class="control-label" for="archetype-property-{{model.alias}}-{{$parent.$index}}-{{$index}}">
|
||||
<span>{{property.label}}</span>
|
||||
<div class="archetypeFieldsetHelpText" ng-show="property.helpText">
|
||||
<small>{{property.helpText}}</small>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<div class="controls">
|
||||
<archetype-property class="archetypeEditor ng-class:property.alias" property="property" fieldset-index="$parent.$index" fieldset="fieldset" archetype-config="model.config" property-config-index="$index" archetype-render-model="model.value" umbraco-property-alias="model.alias" umbraco-form = "form"></archetype-property>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</fieldset>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-show="showAddButton()">
|
||||
<a data-toggle="{{ model.config.fieldsets.length > 1 ? 'dropdown' : ''}}" ng-click="model.config.fieldsets.length == 1 ? addRow(model.config.fieldsets[0].alias, 0) : return" prevent-default>
|
||||
<i class="icon icon-add dropdown-toggle"></i>
|
||||
<localize key="general_add" class="archetypeAddButtonText">Add</localize>
|
||||
</a>
|
||||
<ul class="dropdown-menu umb-actions">
|
||||
<li ng-repeat="fieldsetModel in model.config.fieldsets" ng-click="addRow(fieldsetModel.alias, 0)">
|
||||
<a>
|
||||
<i class="fieldsetIcon icon ng-class:fieldsetModel.icon"></i>
|
||||
<span class="menu-label">{{fieldsetModel.label}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div archetype-custom-view archetype="model"></div>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Archetype",
|
||||
"version": "1.0-beta",
|
||||
"version": "1.2-beta",
|
||||
"url": "http://github.com/imulus/archetype/",
|
||||
"author": "Imulus",
|
||||
"authorUrl": "http://imulus.com/",
|
||||
|
||||
@@ -27,5 +27,8 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/imulus/Archetype.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt-msbuild": "^0.1.12"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user