diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs index c3486f2f2..ecb503451 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs @@ -1,7 +1,9 @@ using System.Linq; using System.Web.Mvc; +using System.Xml.Linq; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Framework.Elements; @@ -14,10 +16,12 @@ namespace Orchard.Layouts.Drivers { public class ElementWrapperPartDriver : ContentPartDriver { private readonly IElementManager _elementManager; private readonly IElementDisplay _elementDisplay; + private readonly IElementSerializer _serializer; - public ElementWrapperPartDriver(IElementManager elementManager, IElementDisplay elementDisplay) { + public ElementWrapperPartDriver(IElementManager elementManager, IElementDisplay elementDisplay, IElementSerializer serializer) { _elementManager = elementManager; _elementDisplay = elementDisplay; + _serializer = serializer; } protected override DriverResult Display(ElementWrapperPart part, string displayType, dynamic shapeHelper) { @@ -63,6 +67,32 @@ namespace Orchard.Layouts.Drivers { }); } + protected override void Exporting(ElementWrapperPart part, ExportContentContext context) { + var describeContext = CreateDescribeContext(part); + var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, part.ElementTypeName); + var data = ElementDataHelper.Deserialize(part.ElementData); + var element = _elementManager.ActivateElement(descriptor, e => e.Data = data); + + _elementManager.Exporting(new[] { element }, new ExportLayoutContext()); + var exportableData = _serializer.Serialize(element); + + context.Element(part.PartDefinition.Name).SetValue(exportableData); + } + + protected override void Importing(ElementWrapperPart part, ImportContentContext context) { + var root = context.Data.Element(part.PartDefinition.Name); + + if (root == null) + return; + + var exportedData = root.Value; + var describeContext = CreateDescribeContext(part); + var element = _serializer.Deserialize(exportedData, describeContext); + + _elementManager.Importing(new[]{element}, new ImportLayoutContext { Session = new ImportContentContextWrapper(context)}); + part.ElementData = element.Data.Serialize(); + } + private static DescribeElementsContext CreateDescribeContext(IContent part) { return new DescribeElementsContext { Content = part diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Migrations.cs index 1ca607b6b..32109eefb 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Migrations.cs @@ -1,5 +1,4 @@ -using System; -using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData; using Orchard.Core.Contents.Extensions; using Orchard.Data.Migration; using Orchard.Layouts.Helpers; @@ -40,6 +39,7 @@ namespace Orchard.Layouts { .WithPart("CommonPart", p => p .WithSetting("OwnerEditorSettings.ShowOwnerEditor", "false") .WithSetting("DateEditorSettings.ShowDateEditor", "false")) + .WithPart("IdentityPart") .WithPart("WidgetPart") .WithPart("LayoutPart") .WithSetting("Stereotype", "Widget") @@ -76,6 +76,7 @@ namespace Orchard.Layouts { .WithSetting("OwnerEditorSettings.ShowOwnerEditor", "false") .WithSetting("DateEditorSettings.ShowDateEditor", "false")) .WithPart("WidgetPart") + .WithPart("IdentityPart") .WithPart("ElementWrapperPart", p => p .WithSetting("ElementWrapperPartSettings.ElementTypeName", elementTypeName)) .WithSetting("Stereotype", "Widget") diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj index c29c4a27b..ace8f4b77 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj @@ -461,9 +461,11 @@ + + diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementSerializer.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementSerializer.cs new file mode 100644 index 000000000..b912290fa --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementSerializer.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Orchard.Layouts.Elements; +using Orchard.Layouts.Framework.Elements; +using Orchard.Layouts.Helpers; + +namespace Orchard.Layouts.Services { + public class ElementSerializer : IElementSerializer { + private readonly IElementManager _elementManager; + private readonly IElementFactory _elementFactory; + + public ElementSerializer(IElementManager elementManager, IElementFactory elementFactory) { + _elementManager = elementManager; + _elementFactory = elementFactory; + } + + public Element Deserialize(string data, DescribeElementsContext describeContext) { + if (String.IsNullOrWhiteSpace(data)) + return null; + + var token = JToken.Parse(data); + var element = ParseNode(node: token, parent: null, index: 0, describeContext: describeContext); + + return element; + } + + public string Serialize(Element element) { + var dto = ToDto(element); + return JToken.FromObject(dto).ToString(Formatting.None); + } + + public object ToDto(Element element, int index = 0) { + var container = element as Container; + var dto = new { + typeName = element.Descriptor.TypeName, + data = element.Data.Serialize(), + exportableData = element.ExportableData.Serialize(), + index = index, + elements = container != null ? container.Elements.Select(ToDto).ToList() : new List(), + isTemplated = element.IsTemplated, + htmlId = element.HtmlId, + htmlClass = element.HtmlClass, + htmlStyle = element.HtmlStyle + }; + return dto; + } + + public Element ParseNode(JToken node, Container parent, int index, DescribeElementsContext describeContext) { + var elementTypeName = (string)node["typeName"]; + + if (String.IsNullOrWhiteSpace(elementTypeName)) + return null; + + var data = (string) node["data"]; + var htmlId = (string) node["htmlId"]; + var htmlClass = (string)node["htmlClass"]; + var htmlStyle = (string)node["htmlStyle"]; + var elementData = ElementDataHelper.Deserialize(data); + var exportableData = ElementDataHelper.Deserialize((string)node["exportableData"]); + var childNodes = node["elements"]; + var elementDescriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, elementTypeName); + + if (elementDescriptor == null) + return null; // This happens if an element exists in a layout, but its type is no longer available due to its feature being disabled. + + var element = _elementFactory.Activate(elementDescriptor, e => { + e.Container = parent; + e.Index = index; + e.Data = elementData; + e.ExportableData = exportableData; + e.HtmlId = htmlId; + e.HtmlClass = htmlClass; + e.HtmlStyle = htmlStyle; + }); + + var container = element as Container; + + if (container != null) + container.Elements = childNodes != null + ? childNodes.Select((x, i) => ParseNode(x, container, i, describeContext)).Where(x => x != null).ToList() + : new List(); + + element.IsTemplated = node.Value("isTemplated"); + + return element; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementSerializer.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementSerializer.cs new file mode 100644 index 000000000..3fa7ef64b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementSerializer.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json.Linq; +using Orchard.Layouts.Elements; +using Orchard.Layouts.Framework.Elements; + +namespace Orchard.Layouts.Services { + public interface IElementSerializer : IDependency { + Element Deserialize(string data, DescribeElementsContext describeContext); + string Serialize(Element element); + object ToDto(Element element, int index = 0); + Element ParseNode(JToken node, Container parent, int index, DescribeElementsContext describeContext); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/LayoutSerializer.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/LayoutSerializer.cs index 92113bd16..92278853f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/LayoutSerializer.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/LayoutSerializer.cs @@ -3,18 +3,13 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Orchard.Layouts.Elements; using Orchard.Layouts.Framework.Elements; -using Orchard.Layouts.Helpers; namespace Orchard.Layouts.Services { public class LayoutSerializer : ILayoutSerializer { - private readonly IElementManager _elementManager; - private readonly IElementFactory _elementFactory; - - public LayoutSerializer(IElementManager elementManager, IElementFactory elementFactory) { - _elementManager = elementManager; - _elementFactory = elementFactory; + private readonly IElementSerializer _elementSerializer; + public LayoutSerializer(IElementSerializer elementSerializer) { + _elementSerializer = elementSerializer; } public IEnumerable Deserialize(string data, DescribeElementsContext describeContext) { @@ -26,7 +21,7 @@ namespace Orchard.Layouts.Services { var token = JToken.Parse(data); var nodes = (JArray)token["elements"]; var elements = nodes != null - ? nodes.Select((x, i) => ParseNode(node: x, parent: null, index: i, describeContext: describeContext)).Where(x => x != null).ToArray() + ? nodes.Select((x, i) => _elementSerializer.ParseNode(node: x, parent: null, index: i, describeContext: describeContext)).Where(x => x != null).ToArray() : emptyList; return elements; @@ -34,66 +29,10 @@ namespace Orchard.Layouts.Services { public string Serialize(IEnumerable elements) { var root = new { - elements = elements.Select(Serialize).ToArray() + elements = elements.Select((x, i) => _elementSerializer.ToDto(x, i)).ToArray() }; return JToken.FromObject(root).ToString(Formatting.None); } - - private static object Serialize(Element element, int index) { - var container = element as Container; - var dto = new { - typeName = element.Descriptor.TypeName, - data = element.Data.Serialize(), - exportableData = element.ExportableData.Serialize(), - index = index, - elements = container != null ? container.Elements.Select(Serialize).ToList() : new List(), - isTemplated = element.IsTemplated, - htmlId = element.HtmlId, - htmlClass = element.HtmlClass, - htmlStyle = element.HtmlStyle - }; - return dto; - } - - private Element ParseNode(JToken node, Container parent, int index, DescribeElementsContext describeContext) { - var elementTypeName = (string)node["typeName"]; - - if (String.IsNullOrWhiteSpace(elementTypeName)) - return null; - - var data = (string) node["data"] ?? (string) node["state"]; // Falling back to "state" node for backwards compatibility. - var htmlId = (string) node["htmlId"]; - var htmlClass = (string)node["htmlClass"]; - var htmlStyle = (string)node["htmlStyle"]; - var elementData = ElementDataHelper.Deserialize(data); - var exportableData = ElementDataHelper.Deserialize((string)node["exportableData"]); - var childNodes = node["elements"]; - var elementDescriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, elementTypeName); - - if (elementDescriptor == null) - return null; // This happens if an element exists in a layout, but its type is no longer available due to its feature being disabled. - - var element = _elementFactory.Activate(elementDescriptor, e => { - e.Container = parent; - e.Index = index; - e.Data = elementData; - e.ExportableData = exportableData; - e.HtmlId = htmlId; - e.HtmlClass = htmlClass; - e.HtmlStyle = htmlStyle; - }); - - var container = element as Container; - - if (container != null) - container.Elements = childNodes != null - ? childNodes.Select((x, i) => ParseNode(x, container, i, describeContext)).Where(x => x != null).ToList() - : new List(); - - element.IsTemplated = node.Value("isTemplated"); - - return element; - } } } \ No newline at end of file