diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj b/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj
index dc7aeabe1..3eb47bfd0 100644
--- a/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj
+++ b/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj
@@ -130,6 +130,11 @@
+
+
+
+
+
diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayout.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayout.cs
new file mode 100644
index 000000000..ca998fd9f
--- /dev/null
+++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayout.cs
@@ -0,0 +1,66 @@
+using System.Collections.Generic;
+using System.Linq;
+using Orchard.ContentManagement;
+using Orchard.DisplayManagement;
+using Orchard.Localization;
+using Orchard.Projections.Descriptors.Layout;
+using Orchard.Projections.Models;
+using Orchard.Projections.Services;
+
+namespace Orchard.Projections.Providers.Layouts {
+ public class RawLayout : ILayoutProvider {
+ private readonly IContentManager _contentManager;
+ protected dynamic Shape { get; set; }
+
+ public RawLayout(IShapeFactory shapeFactory, IContentManager contentManager) {
+ _contentManager = contentManager;
+ Shape = shapeFactory;
+ T = NullLocalizer.Instance;
+ }
+
+ public Localizer T { get; set; }
+
+ public void Describe(DescribeLayoutContext describe) {
+ describe.For("Html", T("Html"),T("Html Layouts"))
+ .Element("Raw", T("Raw"), T("Renders content with custom separators."),
+ DisplayLayout,
+ RenderLayout,
+ "RawLayout"
+ );
+ }
+
+ public LocalizedString DisplayLayout(LayoutContext context) {
+ return T("Renders content with custom separators.");
+ }
+
+ public dynamic RenderLayout(LayoutContext context, IEnumerable layoutComponentResults) {
+ string containerTag = context.State.ContainerTag;
+ string containerId = context.State.ContainerId;
+ string containerClass = context.State.ContainerClass;
+
+ string itemTag = context.State.ItemTag;
+ string itemClass = context.State.ItemClass;
+
+ string prepend = context.State.Prepend;
+ string append = context.State.Append;
+ string separator = context.State.Separator;
+
+ IEnumerable shapes =
+ context.LayoutRecord.Display == (int)LayoutRecord.Displays.Content
+ ? layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType))
+ : layoutComponentResults.Select(x => x.Properties);
+
+ return Shape.Raw(
+ Id: containerId,
+ Items: shapes,
+ Tag: containerTag,
+ Classes: new [] { containerClass },
+ ItemTag: itemTag,
+ ItemClasses: new [] { itemClass },
+ Prepend: prepend,
+ Append: append,
+ Separator: separator
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayoutForms.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayoutForms.cs
new file mode 100644
index 000000000..253de6357
--- /dev/null
+++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayoutForms.cs
@@ -0,0 +1,84 @@
+using System;
+using Orchard.DisplayManagement;
+using Orchard.Forms.Services;
+using Orchard.Localization;
+
+namespace Orchard.Projections.Providers.Layouts {
+
+ public class RawLayoutForms : IFormProvider {
+ protected dynamic Shape { get; set; }
+ public Localizer T { get; set; }
+
+ public RawLayoutForms(
+ IShapeFactory shapeFactory) {
+ Shape = shapeFactory;
+ T = NullLocalizer.Instance;
+ }
+
+ public void Describe(DescribeContext context) {
+ Func form =
+ shape => {
+
+ var f = Shape.Form(
+ Id: "RawLayout",
+ _HtmlProperties: Shape.Fieldset(
+ Title: T("Html properties"),
+ _ContainerTag: Shape.TextBox(
+ Id: "container-tag", Name: "ContainerTag",
+ Title: T("Container tag"),
+ Description: T("The tag of the container. Leave empty for no container."),
+ Classes: new[] { "textMedium", "tokenized" }
+ ),
+ _ContainerId: Shape.TextBox(
+ Id: "container-id", Name: "ContainerId",
+ Title: T("Container id"),
+ Description: T("The id to provide on the container element."),
+ Classes: new[] { "textMedium", "tokenized" }
+ ),
+ _ContainerClass: Shape.TextBox(
+ Id: "container-class", Name: "ContainerClass",
+ Title: T("Container class"),
+ Description: T("The class to provide on the container element."),
+ Classes: new[] { "textMedium", "tokenized" }
+ ),
+ _ItemTag: Shape.TextBox(
+ Id: "item-tag", Name: "ItemTag",
+ Title: T("Item tag"),
+ Description: T("The tag of each item. Leave empty for tag."),
+ Classes: new[] { "textMedium", "tokenized" }
+ ),
+ _ItemClass: Shape.TextBox(
+ Id: "item-class", Name: "ItemClass",
+ Title: T("Item class"),
+ Description: T("The class to provide on each item."),
+ Classes: new[] { "textMedium", "tokenized" }
+ ),
+ _Prepend: Shape.TextBox(
+ Id: "prepend", Name: "Prepend",
+ Title: T("Prepend"),
+ Description: T("Some HTML to insert before the first element."),
+ Classes: new[] { "textMedium", "tokenized" }
+ ),
+ _Separator: Shape.TextBox(
+ Id: "separator", Name: "Separator",
+ Title: T("Separator"),
+ Description: T("Some HTML to insert between two items."),
+ Classes: new[] { "textMedium", "tokenized" }
+ ),
+ _Append: Shape.TextBox(
+ Id: "append", Name: "Append",
+ Title: T("Append"),
+ Description: T("Some HTML to insert after the last element."),
+ Classes: new[] { "textMedium", "tokenized" }
+ )
+ )
+ );
+
+ return f;
+ };
+
+ context.Form("RawLayout", form);
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawShapes.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawShapes.cs
new file mode 100644
index 000000000..d275956b9
--- /dev/null
+++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawShapes.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Web.Mvc;
+using Orchard.DisplayManagement;
+using Orchard.Localization;
+
+namespace Orchard.Projections.Providers.Layouts {
+ public class RawShapes : IDependency {
+ public RawShapes() {
+ T = NullLocalizer.Instance;
+ }
+
+ public Localizer T { get; set; }
+
+ [Shape]
+ public void Raw(dynamic Display, TextWriter Output, HtmlHelper Html, string Id, string Tag, IEnumerable Items, IEnumerable Classes, IDictionary Attributes, string ItemTag, IEnumerable ItemClasses, IDictionary ItemAttributes, string Prepend, string Append, string Separator) {
+ if (Items == null)
+ return;
+
+ var items = Items.ToList();
+ var itemsCount = items.Count;
+
+ if (itemsCount < 1)
+ return;
+
+ var containerTag = String.IsNullOrEmpty(Tag) ? null : GetTagBuilder(Tag, Id, Classes, Attributes);
+ var itemTag = String.IsNullOrEmpty(ItemTag) ? null : GetTagBuilder(ItemTag, string.Empty, ItemClasses, ItemAttributes);
+
+ if (containerTag != null) {
+ Output.Write(containerTag.ToString(TagRenderMode.StartTag));
+ }
+
+ if (!String.IsNullOrEmpty(Prepend)) {
+ Output.Write(Prepend);
+ }
+
+ var first = true;
+
+ foreach (var item in items) {
+ if (!first && !String.IsNullOrEmpty(Separator)) {
+ Output.Write(Separator);
+ }
+
+ if (itemTag != null) {
+ Output.Write(itemTag.ToString(TagRenderMode.StartTag));
+ }
+
+ Output.Write(Display(item));
+
+ if (itemTag != null) {
+ Output.Write(itemTag.ToString(TagRenderMode.EndTag));
+ }
+
+ first = false;
+ }
+
+ if (!String.IsNullOrEmpty(Append)) {
+ Output.Write(Append);
+ }
+
+ if (containerTag != null) {
+ Output.Write(containerTag.ToString(TagRenderMode.EndTag));
+ }
+ }
+
+ static TagBuilder GetTagBuilder(string tagName, string id, IEnumerable classes, IDictionary attributes) {
+ var tagBuilder = new TagBuilder(tagName);
+ tagBuilder.MergeAttributes(attributes, false);
+ foreach (var cssClass in classes ?? Enumerable.Empty())
+ tagBuilder.AddCssClass(cssClass);
+ if (!string.IsNullOrWhiteSpace(id))
+ tagBuilder.GenerateId(id);
+ return tagBuilder;
+ }
+
+ }
+}
diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ShapeLayout.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ShapeLayout.cs
new file mode 100644
index 000000000..581946e44
--- /dev/null
+++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ShapeLayout.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Orchard.ContentManagement;
+using Orchard.DisplayManagement;
+using Orchard.Localization;
+using Orchard.Projections.Descriptors.Layout;
+using Orchard.Projections.Models;
+using Orchard.Projections.Services;
+
+namespace Orchard.Projections.Providers.Layouts {
+ public class ShapeLayout : ILayoutProvider {
+ private readonly IContentManager _contentManager;
+ protected dynamic Shape { get; set; }
+
+ public ShapeLayout(IShapeFactory shapeFactory, IContentManager contentManager) {
+ _contentManager = contentManager;
+ Shape = shapeFactory;
+ T = NullLocalizer.Instance;
+ }
+
+ public Localizer T { get; set; }
+
+ public void Describe(DescribeLayoutContext describe) {
+ describe.For("Html", T("Html"),T("Html Layouts"))
+ .Element("Shape", T("Shape"), T("Uses a specific shape name to render the layout."),
+ DisplayLayout,
+ RenderLayout,
+ "ShapeLayout"
+ );
+ }
+
+ public LocalizedString DisplayLayout(LayoutContext context) {
+ return T("Renders content in a {0} layout", context.State.ShapeType.ToString());
+ }
+
+ public dynamic RenderLayout(LayoutContext context, IEnumerable layoutComponentResults) {
+ string shapeType = context.State.ShapeType;
+
+ dynamic shape = ((IShapeFactory) Shape).Create(shapeType);
+ shape.ContentItems = layoutComponentResults.Select(x => x.ContentItem);
+ shape.BuildShapes= (Func>) (() => context.LayoutRecord.Display == (int)LayoutRecord.Displays.Content
+ ? layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType))
+ : layoutComponentResults.Select(x => x.Properties));
+
+
+ return shape;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ShapeLayoutForms.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ShapeLayoutForms.cs
new file mode 100644
index 000000000..699da1e47
--- /dev/null
+++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ShapeLayoutForms.cs
@@ -0,0 +1,42 @@
+using System;
+using Orchard.DisplayManagement;
+using Orchard.Forms.Services;
+using Orchard.Localization;
+
+namespace Orchard.Projections.Providers.Layouts {
+
+ public class ShapeLayoutForms : IFormProvider {
+ protected dynamic Shape { get; set; }
+ public Localizer T { get; set; }
+
+ public ShapeLayoutForms(
+ IShapeFactory shapeFactory) {
+ Shape = shapeFactory;
+ T = NullLocalizer.Instance;
+ }
+
+ public void Describe(DescribeContext context) {
+ Func form =
+ shape => {
+
+ var f = Shape.Form(
+ Id: "ShapeLayout",
+ _Options: Shape.Fieldset(
+ Title: T("Shape options"),
+ _ShapeType: Shape.TextBox(
+ Id: "shape-type", Name: "ShapeType",
+ Title: T("Shape type"),
+ Description: T("The type of the shape which is used for rendering content items."),
+ Classes: new[] { "textMedium", "tokenized" }
+ )
+ )
+ );
+
+ return f;
+ };
+
+ context.Form("ShapeLayout", form);
+
+ }
+ }
+}
\ No newline at end of file