From 6ff17439e8a14e644b55ff27f4d6b2b4fd4ae4d2 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 11 Nov 2015 15:48:38 +0100 Subject: [PATCH] Implemented Import/Export support for harvesters. Also normalized the way drivers are invoked by moving code from the ElementManager to the ElementDriversCoordinator handler. --- .../Framework/Drivers/ExportElementContext.cs | 12 +- .../Framework/Drivers/ImportElementContext.cs | 15 ++- .../Framework/Elements/ElementDescriptor.cs | 12 ++ .../Elements/ElementRemovingContext.cs | 18 +-- .../Handlers/ElementDriversCoordinator.cs | 34 +++++ .../Handlers/LayoutPartHandler.cs | 26 +++- .../Handlers/WidgetPartHandler.cs | 11 -- .../PlaceableContentElementHarvester.cs | 24 ++++ .../Scripts/placeable-widget-editor.js | 4 +- .../Services/ElementEventHandlerBase.cs | 6 + .../Services/ElementManager.cs | 118 +++++++----------- .../Services/IElementEventHandler.cs | 6 + 12 files changed, 175 insertions(+), 111 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ExportElementContext.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ExportElementContext.cs index c00032302..be60f48e1 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ExportElementContext.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ExportElementContext.cs @@ -3,12 +3,14 @@ using Orchard.Layouts.Models; namespace Orchard.Layouts.Framework.Drivers { public class ExportElementContext { - public ExportElementContext() { - ExportableData = new ElementDataDictionary(); + public ExportElementContext(Element element, ILayoutAspect layout, ElementDataDictionary exportableData) { + Element = element; + Layout = layout; + ExportableData = exportableData; } - public ILayoutAspect Layout { get; set; } - public Element Element { get; set; } - public ElementDataDictionary ExportableData { get; set; } + public ILayoutAspect Layout { get; private set; } + public Element Element { get; private set; } + public ElementDataDictionary ExportableData { get; private set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ImportElementContext.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ImportElementContext.cs index 51d5c3146..7b6e7cb24 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ImportElementContext.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Drivers/ImportElementContext.cs @@ -3,13 +3,16 @@ using Orchard.Layouts.Models; namespace Orchard.Layouts.Framework.Drivers { public class ImportElementContext { - public ImportElementContext() { - ExportableData = new ElementDataDictionary(); + public ImportElementContext(Element element, ILayoutAspect layout, ElementDataDictionary exportableData, IContentImportSession session) { + Element = element; + Layout = layout; + ExportableData = exportableData; + Session = session; } - public ILayoutAspect Layout { get; set; } - public Element Element { get; set; } - public ElementDataDictionary ExportableData { get; set; } - public IContentImportSession Session { get; set; } + public ILayoutAspect Layout { get; private set; } + public Element Element { get; private set; } + public ElementDataDictionary ExportableData { get; private set; } + public IContentImportSession Session { get; private set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementDescriptor.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementDescriptor.cs index 438e102b8..dc8b606f6 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementDescriptor.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementDescriptor.cs @@ -18,7 +18,13 @@ namespace Orchard.Layouts.Framework.Elements { Displaying = context => { }; Editor = context => { }; UpdateEditor = context => { }; + LayoutSaving = context => { }; Removing = context => { }; + Exporting = context => { }; + Exported = context => { }; + Importing = context => { }; + Imported = context => { }; + ImportCompleted = context => { }; StateBag = new Dictionary(); } @@ -34,7 +40,13 @@ namespace Orchard.Layouts.Framework.Elements { public Action Displayed { get; set; } public Action Editor { get; set; } public Action UpdateEditor { get; set; } + public Action LayoutSaving { get; set; } public Action Removing { get; set; } + public Action Exporting { get; set; } + public Action Exported { get; set; } + public Action Importing { get; set; } + public Action Imported { get; set; } + public Action ImportCompleted { get; set; } public bool IsSystemElement { get; set; } public bool EnableEditorDialog { get; set; } public IDictionary StateBag { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementRemovingContext.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementRemovingContext.cs index 753971b54..f047859e8 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementRemovingContext.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Elements/ElementRemovingContext.cs @@ -1,11 +1,13 @@ -namespace Orchard.Layouts.Framework.Elements { - public class ElementRemovingContext : LayoutSavingContext { - public ElementRemovingContext(LayoutSavingContext stub) { - Content = stub.Content; - RemovedElements = stub.RemovedElements; - Updater = stub.Updater; - Elements = stub.Elements; +using Orchard.ContentManagement; + +namespace Orchard.Layouts.Framework.Elements { + public class ElementRemovingContext { + public ElementRemovingContext(Element element, IContent content) { + Element = element; + Content = content; } - public Element Element { get; set; } + + public IContent Content { get; private set; } + public Element Element { get; private set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/ElementDriversCoordinator.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/ElementDriversCoordinator.cs index 904dd08c7..542f51207 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/ElementDriversCoordinator.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/ElementDriversCoordinator.cs @@ -1,5 +1,6 @@ using System; using Orchard.Layouts.Framework.Drivers; +using Orchard.Layouts.Framework.Elements; using Orchard.Layouts.Services; namespace Orchard.Layouts.Handlers { @@ -17,6 +18,34 @@ namespace Orchard.Layouts.Handlers { BuildEditorInternal(context, driver => driver.UpdateEditor(context)); } + public override void LayoutSaving(ElementSavingContext context) { + InvokeDrivers(context.Element, driver => driver.LayoutSaving(context)); + } + + public override void Removing(ElementRemovingContext context) { + InvokeDrivers(context.Element, driver => driver.Removing(context)); + } + + public override void Exporting(ExportElementContext context) { + InvokeDrivers(context.Element, driver => driver.Exporting(context)); + } + + public override void Exported(ExportElementContext context) { + InvokeDrivers(context.Element, driver => driver.Exported(context)); + } + + public override void Importing(ImportElementContext context) { + InvokeDrivers(context.Element, driver => driver.Importing(context)); + } + + public override void Imported(ImportElementContext context) { + InvokeDrivers(context.Element, driver => driver.Imported(context)); + } + + public override void ImportCompleted(ImportElementContext context) { + InvokeDrivers(context.Element, driver => driver.ImportCompleted(context)); + } + private void BuildEditorInternal(ElementEditorContext context, Func action) { var descriptor = context.Element.Descriptor; var drivers = _elementManager.GetDrivers(descriptor); @@ -36,5 +65,10 @@ namespace Orchard.Layouts.Handlers { } } } + + private void InvokeDrivers(Element element, Action action) { + var drivers = _elementManager.GetDrivers(element.Descriptor); + drivers.Invoke(action, Logger); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/LayoutPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/LayoutPartHandler.cs index 0e2c3b37a..7e6981b83 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/LayoutPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/LayoutPartHandler.cs @@ -1,10 +1,13 @@ using System; +using System.Linq; using Orchard.Alias; using Orchard.Autoroute.Models; using Orchard.ContentManagement; using Orchard.ContentManagement.Handlers; using Orchard.Data; using Orchard.DisplayManagement; +using Orchard.Layouts.Framework.Elements; +using Orchard.Layouts.Helpers; using Orchard.Layouts.Models; using Orchard.Layouts.Services; using Orchard.Utility.Extensions; @@ -17,13 +20,15 @@ namespace Orchard.Layouts.Handlers { private readonly IShapeDisplay _shapeDisplay; private readonly ILayoutSerializer _serializer; private readonly IAliasService _aliasService; + private readonly IElementManager _elementManager; public LayoutPartHandler( - IRepository repository, - ILayoutManager layoutManager, - IContentManager contentManager, - IContentPartDisplay contentPartDisplay, - IShapeDisplay shapeDisplay, + IRepository repository, + ILayoutManager layoutManager, + IElementManager elementManager, + IContentManager contentManager, + IContentPartDisplay contentPartDisplay, + IShapeDisplay shapeDisplay, ILayoutSerializer serializer, IAliasService aliasService) { @@ -33,10 +38,12 @@ namespace Orchard.Layouts.Handlers { _shapeDisplay = shapeDisplay; _serializer = serializer; _aliasService = aliasService; + _elementManager = elementManager; Filters.Add(StorageFilter.For(repository)); OnPublished(UpdateTemplateClients); OnIndexing(IndexLayout); + OnRemoved(RemoveElements); } private void IndexLayout(IndexContentContext context, LayoutPart part) { @@ -87,6 +94,15 @@ namespace Orchard.Layouts.Handlers { } } + private void RemoveElements(RemoveContentContext context, LayoutPart part) { + var elements = _layoutManager.LoadElements(part).ToList(); + var savingContext = new LayoutSavingContext { + Content = part, + RemovedElements = elements + }; + _elementManager.Removing(savingContext); + } + private bool IsHomePage(IContent content) { var homepage = _aliasService.Get(String.Empty); var displayRouteValues = _contentManager.GetItemMetadata(content).DisplayRouteValues; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/WidgetPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/WidgetPartHandler.cs index 75d3ecf3a..90d464aa8 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/WidgetPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Handlers/WidgetPartHandler.cs @@ -11,20 +11,9 @@ namespace Orchard.Layouts.Handlers { public WidgetPartHandler(IOrchardServices orchardServices) { _orchardServices = orchardServices; - OnUpdating(PreProcessPlacedWidget); OnUpdated(PostProcessPlacedWidget); } - private void PreProcessPlacedWidget(UpdateContentContext context, WidgetPart part) { - if (!part.IsPlaceableContent()) - return; - - // This widget will be placed on a layout and thus will be created outside - // the context of the widget admin controller, which would have provided a default position value. - // Since the position property is required, we need to set it here to prevent a model validation error when updating. - part.Position = "0"; - } - private void PostProcessPlacedWidget(UpdateContentContext context, WidgetPart part) { if (!part.IsPlaceableContent()) return; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs index 28ad2ad8d..c03d5350c 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs @@ -39,6 +39,8 @@ namespace Orchard.Layouts.Providers { ToolboxIcon = "\uf1b2", EnableEditorDialog = true, Removing = RemoveContentItem, + Exporting = ExportElement, + Importing = ImportElement, StateBag = new Dictionary { { "ContentTypeName", contentTypeDefinition.Name } } @@ -133,6 +135,28 @@ namespace Orchard.Layouts.Providers { _contentManager.Value.Remove(contentItem); } + private void ExportElement(ExportElementContext context) { + var element = (PlaceableContentItem)context.Element; + var contentItemId = element.ContentItemId; + var contentItem = contentItemId != null ? _contentManager.Value.Get(contentItemId.Value, VersionOptions.Latest) : default(ContentItem); + var contentItemIdentity = contentItem != null ? _contentManager.Value.GetItemMetadata(contentItem).Identity.ToString() : default(string); + + if (contentItemIdentity != null) + context.ExportableData["ContentItemId"] = contentItemIdentity; + } + + private void ImportElement(ImportElementContext context) { + var contentItemIdentity = context.ExportableData.Get("ContentItemId"); + + if (String.IsNullOrWhiteSpace(contentItemIdentity)) + return; + + var contentItem = context.Session.GetItemFromSession(contentItemIdentity); + var element = (PlaceableContentItem)context.Element; + + element.ContentItemId = contentItem != null ? contentItem.Id : default(int?); + } + private IEnumerable GetPlaceableContentTypeDefinitions() { // Select all types that have either "Placeable" set ot true or the "Widget" stereotype. var contentTypeDefinitionsQuery = diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/placeable-widget-editor.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/placeable-widget-editor.js index c6b0d57d9..32474bae5 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/placeable-widget-editor.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/placeable-widget-editor.js @@ -1,7 +1,9 @@ (function ($) { - // Hide the Layer, Zone, and Position fieldsets. + // Hide the Layer, Zone, and Position fieldsets and set a value for the required fields. $(function() { var fieldsets = $("#element-properties .edit-widget fieldset").slice(0, 3); fieldsets.hide(); + + $("input[name='WidgetPart.Position']").val("0"); }); })(jQuery); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementEventHandlerBase.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementEventHandlerBase.cs index d82a816d7..1a612824d 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementEventHandlerBase.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementEventHandlerBase.cs @@ -11,6 +11,12 @@ namespace Orchard.Layouts.Services { public virtual void Displayed(ElementDisplayedContext context) { } public virtual void BuildEditor(ElementEditorContext context) { } public virtual void UpdateEditor(ElementEditorContext context) { } + public virtual void LayoutSaving(ElementSavingContext context) { } public virtual void Removing(ElementRemovingContext context) { } + public virtual void Exporting(ExportElementContext context) { } + public virtual void Exported(ExportElementContext context) { } + public virtual void Importing(ImportElementContext context) { } + public virtual void Imported(ImportElementContext context) { } + public virtual void ImportCompleted(ImportElementContext context) { } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs index 9287cc39a..8f42f414b 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs @@ -141,85 +141,68 @@ namespace Orchard.Layouts.Services { public void Saving(LayoutSavingContext context) { var elements = context.Elements.Flatten(); - InvokeDriver(elements, (driver, element) => driver.LayoutSaving(new ElementSavingContext(context) { - Element = element - })); + + foreach (var element in elements) { + var savingContext = new ElementSavingContext(context); + _elementEventHandler.LayoutSaving(savingContext); + element.Descriptor.LayoutSaving(savingContext); + } } public void Removing(LayoutSavingContext context) { - var elementInstances = context.RemovedElements.Flatten().ToList(); + var elements = context.RemovedElements.Flatten().ToList(); - InvokeElementAction(elementInstances, (elementInstance) => { - var elementContext = new ElementRemovingContext(context) { - Element = elementInstance - }; - _elementEventHandler.Removing(elementContext); - elementInstance.Descriptor.Removing(elementContext); - }); - - InvokeDriver(elementInstances, (driver, elementInstance) => driver.Removing(new ElementRemovingContext(context) { - Element = elementInstance - })); + foreach (var element in elements) { + var removingContext = new ElementRemovingContext(element, context.Content); + _elementEventHandler.Removing(removingContext); + element.Descriptor.Removing(removingContext); + } } public void Exporting(IEnumerable elements, ExportLayoutContext context) { - InvokeDriver(elements, (driver, element) => { - var exportElementContext = new ExportElementContext { - Layout = context.Layout, - Element = element, - ExportableData = element.ExportableData - }; - driver.Exporting(exportElementContext); - element.ExportableData = new ElementDataDictionary(exportElementContext.ExportableData); - }); + foreach (var element in elements) { + var exportingContext = new ExportElementContext(element, context.Layout, element.ExportableData ?? new ElementDataDictionary()); + _elementEventHandler.Exporting(exportingContext); + element.Descriptor.Exporting(exportingContext); + + // Update potentially modified ExportableData. + element.ExportableData = new ElementDataDictionary(exportingContext.ExportableData); + } } public void Exported(IEnumerable elements, ExportLayoutContext context) { - InvokeDriver(elements, (driver, element) => { - var exportElementContext = new ExportElementContext { - Layout = context.Layout, - Element = element, - ExportableData = element.ExportableData - }; - driver.Exported(exportElementContext); - element.ExportableData = new ElementDataDictionary(exportElementContext.ExportableData); - }); + foreach (var element in elements) { + var exportingContext = new ExportElementContext(element, context.Layout, element.ExportableData ?? new ElementDataDictionary()); + _elementEventHandler.Exported(exportingContext); + element.Descriptor.Exported(exportingContext); + + // Update potentially modified ExportableData. + element.ExportableData = new ElementDataDictionary(exportingContext.ExportableData); + } } public void Importing(IEnumerable elements, ImportLayoutContext context) { - InvokeDriver(elements, (driver, element) => { - var importElementContext = new ImportElementContext { - Layout = context.Layout, - Element = element, - ExportableData = element.ExportableData, - Session = context.Session - }; - driver.Importing(importElementContext); - }); + foreach (var element in elements) { + var importingContext = new ImportElementContext(element, context.Layout, element.ExportableData ?? new ElementDataDictionary(), context.Session); + _elementEventHandler.Importing(importingContext); + element.Descriptor.Importing(importingContext); + } } public void Imported(IEnumerable elements, ImportLayoutContext context) { - InvokeDriver(elements, (driver, element) => { - var importElementContext = new ImportElementContext { - Layout = context.Layout, - Element = element, - ExportableData = element.ExportableData, - Session = context.Session - }; - driver.Imported(importElementContext); - }); + foreach (var element in elements) { + var importingContext = new ImportElementContext(element, context.Layout, element.ExportableData ?? new ElementDataDictionary(), context.Session); + _elementEventHandler.Imported(importingContext); + element.Descriptor.Imported(importingContext); + } } public void ImportCompleted(IEnumerable elements, ImportLayoutContext context) { - InvokeDriver(elements, (driver, element) => { - var importElementContext = new ImportElementContext { - Layout = context.Layout, - Element = element, - ExportableData = element.ExportableData, - Session = context.Session - }; - driver.ImportCompleted(importElementContext); - }); + foreach (var element in elements) { + var importingContext = new ImportElementContext(element, context.Layout, element.ExportableData ?? new ElementDataDictionary(), context.Session); + _elementEventHandler.ImportCompleted(importingContext); + element.Descriptor.ImportCompleted(importingContext); + } } private IDictionary GetCategories() { @@ -234,21 +217,6 @@ namespace Orchard.Layouts.Services { return dictionary; } - private void InvokeElementAction(IEnumerable elements, Action action) { - foreach (var element in elements) { - action(element); - } - } - - private void InvokeDriver(IEnumerable elements, Action driverAction) { - foreach (var element in elements) { - var drivers = GetDrivers(element.Descriptor); - foreach (var driver in drivers) { - driverAction(driver, element); - } - } - } - private static bool IsElementType(IElementDriver elementDriver, Type elementType) { var driverType = elementDriver.GetType(); var driverElementType = driverType.BaseType.GenericTypeArguments[0]; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementEventHandler.cs index d27125bcc..578530c07 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementEventHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementEventHandler.cs @@ -12,6 +12,12 @@ namespace Orchard.Layouts.Services { void Displayed(ElementDisplayedContext context); void BuildEditor(ElementEditorContext context); void UpdateEditor(ElementEditorContext context); + void LayoutSaving(ElementSavingContext context); void Removing(ElementRemovingContext context); + void Exporting(ExportElementContext context); + void Exported(ExportElementContext context); + void Importing(ImportElementContext context); + void Imported(ImportElementContext context); + void ImportCompleted(ImportElementContext context); } } \ No newline at end of file