mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Implementing admin placement for content type editors
--HG-- branch : 1.x
This commit is contained in:
@@ -222,6 +222,7 @@
|
|||||||
<Compile Include="Settings\Migrations.cs" />
|
<Compile Include="Settings\Migrations.cs" />
|
||||||
<Compile Include="Settings\Drivers\SiteSettingsPartDriver.cs" />
|
<Compile Include="Settings\Drivers\SiteSettingsPartDriver.cs" />
|
||||||
<Compile Include="Settings\Routes.cs" />
|
<Compile Include="Settings\Routes.cs" />
|
||||||
|
<Compile Include="Settings\Tokens\SettingsTokens.cs" />
|
||||||
<Compile Include="Settings\ViewModels\SiteCulturesViewModel.cs" />
|
<Compile Include="Settings\ViewModels\SiteCulturesViewModel.cs" />
|
||||||
<Compile Include="Settings\Metadata\ContentDefinitionManager.cs" />
|
<Compile Include="Settings\Metadata\ContentDefinitionManager.cs" />
|
||||||
<Compile Include="Settings\Metadata\Records\ContentFieldDefinitionRecord.cs" />
|
<Compile Include="Settings\Metadata\Records\ContentFieldDefinitionRecord.cs" />
|
||||||
|
@@ -1,14 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.MetaData;
|
using Orchard.ContentManagement.MetaData;
|
||||||
using Orchard.ContentManagement.MetaData.Models;
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
|
using Orchard.ContentTypes.Extensions;
|
||||||
using Orchard.ContentTypes.Services;
|
using Orchard.ContentTypes.Services;
|
||||||
|
using Orchard.ContentTypes.Settings;
|
||||||
using Orchard.ContentTypes.ViewModels;
|
using Orchard.ContentTypes.ViewModels;
|
||||||
using Orchard.Core.Contents.Controllers;
|
using Orchard.Core.Contents.Controllers;
|
||||||
using Orchard.Core.Contents.Settings;
|
using Orchard.Core.Contents.Settings;
|
||||||
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
|
using Orchard.Logging;
|
||||||
|
using Orchard.UI;
|
||||||
using Orchard.UI.Notify;
|
using Orchard.UI.Notify;
|
||||||
using Orchard.Utility.Extensions;
|
using Orchard.Utility.Extensions;
|
||||||
|
|
||||||
@@ -16,17 +22,30 @@ namespace Orchard.ContentTypes.Controllers {
|
|||||||
public class AdminController : Controller, IUpdateModel {
|
public class AdminController : Controller, IUpdateModel {
|
||||||
private readonly IContentDefinitionService _contentDefinitionService;
|
private readonly IContentDefinitionService _contentDefinitionService;
|
||||||
private readonly IContentDefinitionManager _contentDefinitionManager;
|
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||||
|
private readonly IPlacementService _placementService;
|
||||||
|
private readonly Lazy<IEnumerable<IShellSettingsManagerEventHandler>> _settingsManagerEventHandlers;
|
||||||
|
private readonly ShellSettings _settings;
|
||||||
|
|
||||||
public AdminController(IOrchardServices orchardServices, IContentDefinitionService contentDefinitionService, IContentDefinitionManager contentDefinitionManager) {
|
public AdminController(
|
||||||
|
IOrchardServices orchardServices,
|
||||||
|
IContentDefinitionService contentDefinitionService,
|
||||||
|
IContentDefinitionManager contentDefinitionManager,
|
||||||
|
IPlacementService placementService,
|
||||||
|
Lazy<IEnumerable<IShellSettingsManagerEventHandler>> settingsManagerEventHandlers,
|
||||||
|
ShellSettings settings
|
||||||
|
) {
|
||||||
Services = orchardServices;
|
Services = orchardServices;
|
||||||
_contentDefinitionService = contentDefinitionService;
|
_contentDefinitionService = contentDefinitionService;
|
||||||
_contentDefinitionManager = contentDefinitionManager;
|
_contentDefinitionManager = contentDefinitionManager;
|
||||||
|
_placementService = placementService;
|
||||||
|
_settingsManagerEventHandlers = settingsManagerEventHandlers;
|
||||||
|
_settings = settings;
|
||||||
T = NullLocalizer.Instance;
|
T = NullLocalizer.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOrchardServices Services { get; private set; }
|
public IOrchardServices Services { get; private set; }
|
||||||
public Localizer T { get; set; }
|
public Localizer T { get; set; }
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
public ActionResult Index() { return List(); }
|
public ActionResult Index() { return List(); }
|
||||||
|
|
||||||
#region Types
|
#region Types
|
||||||
@@ -116,6 +135,89 @@ namespace Orchard.ContentTypes.Controllers {
|
|||||||
return View(typeViewModel);
|
return View(typeViewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActionResult EditPlacement(string id) {
|
||||||
|
if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content type.")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
|
||||||
|
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(id);
|
||||||
|
|
||||||
|
if (contentTypeDefinition == null)
|
||||||
|
return HttpNotFound();
|
||||||
|
|
||||||
|
var content = Services.ContentManager.New(id);
|
||||||
|
var shape = Services.ContentManager.BuildEditor(content);
|
||||||
|
|
||||||
|
var placementModel = new EditPlacementViewModel {
|
||||||
|
PlacementSettings = contentTypeDefinition.GetPlacement(PlacementType.Editor),
|
||||||
|
AllPlacements = _placementService.GetEditorPlacement(id).OrderBy(x => x.PlacementSettings.Position, new FlatPositionComparer()).ThenBy(x => x.PlacementSettings.ShapeType).ToList(),
|
||||||
|
ContentTypeDefinition = contentTypeDefinition,
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(placementModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost, ActionName("EditPlacement")]
|
||||||
|
[FormValueRequired("submit.Save")]
|
||||||
|
public ActionResult EditPlacementPost(string id, EditPlacementViewModel viewModel) {
|
||||||
|
if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content type.")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
|
||||||
|
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(id);
|
||||||
|
|
||||||
|
if (contentTypeDefinition == null)
|
||||||
|
return HttpNotFound();
|
||||||
|
|
||||||
|
var allPlacements = _placementService.GetEditorPlacement(id).ToList();
|
||||||
|
var result = new List<PlacementSettings>(contentTypeDefinition.GetPlacement(PlacementType.Editor));
|
||||||
|
|
||||||
|
contentTypeDefinition.ResetPlacement(PlacementType.Editor);
|
||||||
|
|
||||||
|
foreach(var driverPlacement in viewModel.AllPlacements) {
|
||||||
|
// if the placement has changed, persist it
|
||||||
|
if (!allPlacements.Any(x => x.PlacementSettings.Equals(driverPlacement.PlacementSettings))) {
|
||||||
|
result = result.Where(x => !x.IsSameAs(driverPlacement.PlacementSettings)).ToList();
|
||||||
|
result.Add(driverPlacement.PlacementSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(var placementSetting in result) {
|
||||||
|
contentTypeDefinition.Placement(PlacementType.Editor,
|
||||||
|
placementSetting.ShapeType,
|
||||||
|
placementSetting.Differentiator,
|
||||||
|
placementSetting.Zone,
|
||||||
|
placementSetting.Position);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// persist changes
|
||||||
|
_contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition);
|
||||||
|
|
||||||
|
_settingsManagerEventHandlers.Value.Invoke(x => x.Saved(_settings), Logger);
|
||||||
|
|
||||||
|
return RedirectToAction("EditPlacement", new {id});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost, ActionName("EditPlacement")]
|
||||||
|
[FormValueRequired("submit.Restore")]
|
||||||
|
public ActionResult EditPlacementRestorePost(string id, EditPlacementViewModel viewModel) {
|
||||||
|
if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content type.")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
|
||||||
|
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(id);
|
||||||
|
|
||||||
|
if (contentTypeDefinition == null)
|
||||||
|
return HttpNotFound();
|
||||||
|
|
||||||
|
contentTypeDefinition.ResetPlacement(PlacementType.Editor);
|
||||||
|
|
||||||
|
// persist changes
|
||||||
|
_contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition);
|
||||||
|
|
||||||
|
_settingsManagerEventHandlers.Value.Invoke(x => x.Saved(_settings), Logger);
|
||||||
|
|
||||||
|
return RedirectToAction("EditPlacement", new { id });
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost, ActionName("Edit")]
|
[HttpPost, ActionName("Edit")]
|
||||||
[FormValueRequired("submit.Save")]
|
[FormValueRequired("submit.Save")]
|
||||||
public ActionResult EditPOST(string id) {
|
public ActionResult EditPOST(string id) {
|
||||||
|
@@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web.Script.Serialization;
|
||||||
|
using Orchard.ContentManagement.MetaData.Builders;
|
||||||
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
|
using Orchard.ContentTypes.Settings;
|
||||||
|
|
||||||
|
namespace Orchard.ContentTypes.Extensions {
|
||||||
|
public enum PlacementType {
|
||||||
|
Display,
|
||||||
|
Editor
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MetadataExtensions {
|
||||||
|
/// <summary>
|
||||||
|
/// Removes any custom placement for a specific shape
|
||||||
|
/// </summary>
|
||||||
|
public static ContentTypeDefinitionBuilder ResetPlacement(this ContentTypeDefinitionBuilder builder, PlacementType placementType, string shapeType, string differentiator) {
|
||||||
|
var serializer = new JavaScriptSerializer();
|
||||||
|
var placementSettings = GetPlacement(builder.Build(), placementType).ToList();
|
||||||
|
|
||||||
|
placementSettings = placementSettings.Where(x => x.ShapeType != shapeType && x.Differentiator != differentiator).ToList();
|
||||||
|
|
||||||
|
var placement = serializer.Serialize(placementSettings.ToArray());
|
||||||
|
|
||||||
|
return builder.WithSetting("ContentTypeSettings.Placement." + placementType, placement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes any custom placement
|
||||||
|
/// </summary>
|
||||||
|
public static ContentTypeDefinitionBuilder ResetPlacement(this ContentTypeDefinitionBuilder builder, PlacementType placementType) {
|
||||||
|
return builder.WithSetting("ContentTypeSettings.Placement." + placementType, String.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a custom placement
|
||||||
|
/// </summary>
|
||||||
|
public static ContentTypeDefinitionBuilder Placement(this ContentTypeDefinitionBuilder builder, PlacementType placementType, string shapeType, string differentiator, string zone, string position) {
|
||||||
|
var serializer = new JavaScriptSerializer();
|
||||||
|
var placementSettings = GetPlacement(builder.Build(), placementType).ToList();
|
||||||
|
|
||||||
|
placementSettings = placementSettings.Where(x => x.ShapeType != shapeType && x.Differentiator != differentiator).ToList();
|
||||||
|
|
||||||
|
placementSettings.Add(new PlacementSettings {
|
||||||
|
ShapeType = shapeType,
|
||||||
|
Differentiator = differentiator,
|
||||||
|
Zone = zone,
|
||||||
|
Position = position
|
||||||
|
});
|
||||||
|
|
||||||
|
var placement = serializer.Serialize(placementSettings.ToArray());
|
||||||
|
|
||||||
|
return builder.WithSetting("ContentTypeSettings.Placement." + placementType, placement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a placement the string representation of a placement
|
||||||
|
/// </summary>
|
||||||
|
public static ContentTypeDefinition Placement(this ContentTypeDefinition builder, PlacementType placementType, string shapeType, string differentiator, string zone, string position) {
|
||||||
|
var serializer = new JavaScriptSerializer();
|
||||||
|
var placementSettings = GetPlacement(builder, placementType).ToList();
|
||||||
|
|
||||||
|
placementSettings = placementSettings.Where(x => !x.IsSameAs(new PlacementSettings { ShapeType = shapeType, Differentiator = differentiator })).ToList();
|
||||||
|
|
||||||
|
placementSettings.Add(new PlacementSettings {
|
||||||
|
ShapeType = shapeType,
|
||||||
|
Differentiator = differentiator,
|
||||||
|
Zone = zone,
|
||||||
|
Position = position
|
||||||
|
});
|
||||||
|
|
||||||
|
var placement = serializer.Serialize(placementSettings.ToArray());
|
||||||
|
builder.Settings["ContentTypeSettings.Placement." + placementType] = placement;
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a placement the string representation of a placement
|
||||||
|
/// </summary>
|
||||||
|
public static ContentTypeDefinition ResetPlacement(this ContentTypeDefinition builder, PlacementType placementType) {
|
||||||
|
builder.Settings["ContentTypeSettings.Placement." + placementType] = String.Empty;
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlacementSettings[] GetPlacement(this ContentTypeDefinition contentTypeDefinition, PlacementType placementType) {
|
||||||
|
var currentSettings = contentTypeDefinition.Settings;
|
||||||
|
string placement;
|
||||||
|
var serializer = new JavaScriptSerializer();
|
||||||
|
|
||||||
|
currentSettings.TryGetValue("ContentTypeSettings.Placement." + placementType, out placement);
|
||||||
|
|
||||||
|
return String.IsNullOrEmpty(placement) ? new PlacementSettings[0] : serializer.Deserialize<PlacementSettings[]>(placement);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -7,3 +7,4 @@ OrchardVersion: 1.4.1
|
|||||||
Description: ContentTypes modules enables the creation and alteration of content types not based on code.
|
Description: ContentTypes modules enables the creation and alteration of content types not based on code.
|
||||||
Dependencies: Contents
|
Dependencies: Contents
|
||||||
Category: Content
|
Category: Content
|
||||||
|
Priority: -10
|
||||||
|
@@ -35,12 +35,14 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="ClaySharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core">
|
<Reference Include="System.Core">
|
||||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="System.Web.Extensions" />
|
||||||
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||||
@@ -49,9 +51,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AdminMenu.cs" />
|
<Compile Include="AdminMenu.cs" />
|
||||||
|
<Compile Include="Extensions\MetadataExtensions.cs" />
|
||||||
<Compile Include="ResourceManifest.cs" />
|
<Compile Include="ResourceManifest.cs" />
|
||||||
<Compile Include="Extensions\StringExtensions.cs" />
|
<Compile Include="Extensions\StringExtensions.cs" />
|
||||||
|
<Compile Include="Services\ContentTypePlacementStrategy.cs" />
|
||||||
|
<Compile Include="Services\IPlacementService.cs" />
|
||||||
|
<Compile Include="Services\PlacementService.cs" />
|
||||||
<Compile Include="Settings\EditorEvents.cs" />
|
<Compile Include="Settings\EditorEvents.cs" />
|
||||||
|
<Compile Include="Settings\PlacementSettings.cs" />
|
||||||
<Compile Include="ViewModels\AddPartsViewModel.cs" />
|
<Compile Include="ViewModels\AddPartsViewModel.cs" />
|
||||||
<Compile Include="Controllers\AdminController.cs" />
|
<Compile Include="Controllers\AdminController.cs" />
|
||||||
<Compile Include="Permissions.cs" />
|
<Compile Include="Permissions.cs" />
|
||||||
@@ -65,6 +72,7 @@
|
|||||||
<Compile Include="ViewModels\EditFieldViewModel.cs" />
|
<Compile Include="ViewModels\EditFieldViewModel.cs" />
|
||||||
<Compile Include="ViewModels\EditPartFieldViewModel.cs" />
|
<Compile Include="ViewModels\EditPartFieldViewModel.cs" />
|
||||||
<Compile Include="ViewModels\EditPartViewModel.cs" />
|
<Compile Include="ViewModels\EditPartViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\EditPlacementViewModel.cs" />
|
||||||
<Compile Include="ViewModels\EditTypePartViewModel.cs" />
|
<Compile Include="ViewModels\EditTypePartViewModel.cs" />
|
||||||
<Compile Include="ViewModels\ListContentPartsViewModel.cs" />
|
<Compile Include="ViewModels\ListContentPartsViewModel.cs" />
|
||||||
<Compile Include="ViewModels\RemoveFieldViewModel.cs" />
|
<Compile Include="ViewModels\RemoveFieldViewModel.cs" />
|
||||||
@@ -76,6 +84,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Module.txt" />
|
<Content Include="Module.txt" />
|
||||||
|
<Content Include="Styles\Images\move.gif" />
|
||||||
<Content Include="Styles\orchard-contenttypes-admin.css" />
|
<Content Include="Styles\orchard-contenttypes-admin.css" />
|
||||||
<Content Include="Views\Admin\AddFieldTo.cshtml" />
|
<Content Include="Views\Admin\AddFieldTo.cshtml" />
|
||||||
<Content Include="Views\Admin\AddPartsTo.cshtml" />
|
<Content Include="Views\Admin\AddPartsTo.cshtml" />
|
||||||
@@ -115,6 +124,10 @@
|
|||||||
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||||
<Name>Orchard.Core</Name>
|
<Name>Orchard.Core</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\Orchard.Themes\Orchard.Themes.csproj">
|
||||||
|
<Project>{CDE24A24-01D3-403C-84B9-37722E18DFB7}</Project>
|
||||||
|
<Name>Orchard.Themes</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="web.config" />
|
<Content Include="web.config" />
|
||||||
@@ -125,6 +138,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Views\DefinitionTemplates\ContentTypeSettingsViewModel.cshtml" />
|
<Content Include="Views\DefinitionTemplates\ContentTypeSettingsViewModel.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\Admin\EditPlacement.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Orchard.ContentManagement.MetaData;
|
||||||
|
using Orchard.ContentTypes.Settings;
|
||||||
|
using Orchard.DisplayManagement.Descriptors;
|
||||||
|
using Orchard.ContentTypes.Extensions;
|
||||||
|
using Orchard.Environment;
|
||||||
|
using Orchard.Environment.Configuration;
|
||||||
|
using Orchard.Environment.Extensions.Models;
|
||||||
|
|
||||||
|
namespace Orchard.ContentTypes.Services {
|
||||||
|
public class TypePlacement {
|
||||||
|
public PlacementSettings Placement { get; set; }
|
||||||
|
public string ContentType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ContentTypePlacementStrategy : IShapeTableEventHandler {
|
||||||
|
private readonly Work<IContentDefinitionManager> _contentDefinitionManager;
|
||||||
|
|
||||||
|
public ContentTypePlacementStrategy(Work<IContentDefinitionManager> contentDefinitionManager) {
|
||||||
|
_contentDefinitionManager = contentDefinitionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Feature Feature { get; set; }
|
||||||
|
|
||||||
|
public void ShapeTableCreated(ShapeTable shapeTable) {
|
||||||
|
|
||||||
|
var typeDefinitions = _contentDefinitionManager.Value.ListTypeDefinitions();
|
||||||
|
var allPlacements = typeDefinitions.SelectMany(td => td.GetPlacement(PlacementType.Editor).Select(p => new TypePlacement { Placement = p, ContentType = td.Name }) );
|
||||||
|
|
||||||
|
// group all placement settings by shape type
|
||||||
|
var shapePlacements = allPlacements.GroupBy(x => x.Placement.ShapeType).ToDictionary(x => x.Key, y=> y.ToList());
|
||||||
|
|
||||||
|
// create a new predicate in a ShapeTableDescriptor has a custom placement
|
||||||
|
foreach(var shapeType in shapeTable.Descriptors.Keys) {
|
||||||
|
List<TypePlacement> customPlacements;
|
||||||
|
if(shapePlacements.TryGetValue(shapeType, out customPlacements)) {
|
||||||
|
var descriptor = shapeTable.Descriptors[shapeType];
|
||||||
|
// there are some custom placements, build a predicate
|
||||||
|
var placement = descriptor.Placement;
|
||||||
|
|
||||||
|
foreach(var customPlacement in customPlacements) {
|
||||||
|
// create local variables to prevent LINQ issues
|
||||||
|
var placementShapeType = customPlacement.Placement.ShapeType;
|
||||||
|
var type = customPlacement.ContentType;
|
||||||
|
var differentiator = customPlacement.Placement.Differentiator;
|
||||||
|
var location = customPlacement.Placement.Zone;
|
||||||
|
if(!String.IsNullOrEmpty(customPlacement.Placement.Position)) {
|
||||||
|
location = String.Concat(location, ":", customPlacement.Placement.Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.Placement = ctx => {
|
||||||
|
var nextPlacement = placement(ctx);
|
||||||
|
if(ctx.DisplayType == null && ((ctx.Differentiator ?? "") == (differentiator ?? "")) && ctx.ContentType == type) {
|
||||||
|
nextPlacement.Location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextPlacement;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.ContentTypes.Settings;
|
||||||
|
|
||||||
|
namespace Orchard.ContentTypes.Services {
|
||||||
|
public interface IPlacementService : IDependency {
|
||||||
|
IEnumerable<DriverResultPlacement> GetDisplayPlacement(string contentType);
|
||||||
|
IEnumerable<DriverResultPlacement> GetEditorPlacement(string contentType);
|
||||||
|
IEnumerable<string> GetZones();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,254 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Routing;
|
||||||
|
using ClaySharp.Implementation;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.Drivers;
|
||||||
|
using Orchard.ContentManagement.Handlers;
|
||||||
|
using Orchard.ContentTypes.Settings;
|
||||||
|
using Orchard.DisplayManagement;
|
||||||
|
using Orchard.DisplayManagement.Descriptors;
|
||||||
|
using Orchard.Environment.Extensions;
|
||||||
|
using Orchard.FileSystems.VirtualPath;
|
||||||
|
using Orchard.Logging;
|
||||||
|
using Orchard.Themes.Services;
|
||||||
|
using Orchard.UI.Zones;
|
||||||
|
|
||||||
|
namespace Orchard.ContentTypes.Services {
|
||||||
|
|
||||||
|
public class DriverResultPlacement {
|
||||||
|
public PlacementSettings PlacementSettings { get; set; }
|
||||||
|
public DriverResult ShapeResult { get; set; }
|
||||||
|
public dynamic Shape { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlacementService : IPlacementService {
|
||||||
|
private readonly IContentManager _contentManager;
|
||||||
|
private readonly ISiteThemeService _siteThemeService;
|
||||||
|
private readonly IExtensionManager _extensionManager;
|
||||||
|
private readonly IShapeFactory _shapeFactory;
|
||||||
|
private readonly IShapeTableLocator _shapeTableLocator;
|
||||||
|
private readonly RequestContext _requestContext;
|
||||||
|
private readonly IEnumerable<IContentPartDriver> _contentPartDrivers;
|
||||||
|
private readonly IEnumerable<IContentFieldDriver> _contentFieldDrivers;
|
||||||
|
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||||
|
private readonly IWorkContextAccessor _workContextAccessor;
|
||||||
|
|
||||||
|
public PlacementService(
|
||||||
|
IContentManager contentManager,
|
||||||
|
ISiteThemeService siteThemeService,
|
||||||
|
IExtensionManager extensionManager,
|
||||||
|
IShapeFactory shapeFactory,
|
||||||
|
IShapeTableLocator shapeTableLocator,
|
||||||
|
RequestContext requestContext,
|
||||||
|
IEnumerable<IContentPartDriver> contentPartDrivers,
|
||||||
|
IEnumerable<IContentFieldDriver> contentFieldDrivers,
|
||||||
|
IVirtualPathProvider virtualPathProvider,
|
||||||
|
IWorkContextAccessor workContextAccessor
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_contentManager = contentManager;
|
||||||
|
_siteThemeService = siteThemeService;
|
||||||
|
_extensionManager = extensionManager;
|
||||||
|
_shapeFactory = shapeFactory;
|
||||||
|
_shapeTableLocator = shapeTableLocator;
|
||||||
|
_requestContext = requestContext;
|
||||||
|
_contentPartDrivers = contentPartDrivers;
|
||||||
|
_contentFieldDrivers = contentFieldDrivers;
|
||||||
|
_virtualPathProvider = virtualPathProvider;
|
||||||
|
_workContextAccessor = workContextAccessor;
|
||||||
|
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<DriverResultPlacement> GetDisplayPlacement(string contentType) {
|
||||||
|
var content = _contentManager.New(contentType);
|
||||||
|
const string actualDisplayType = "Detail";
|
||||||
|
|
||||||
|
dynamic itemShape = CreateItemShape("Content");
|
||||||
|
itemShape.ContentItem = content;
|
||||||
|
itemShape.Metadata.DisplayType = actualDisplayType;
|
||||||
|
|
||||||
|
var context = new BuildDisplayContext(itemShape, content, actualDisplayType, String.Empty, _shapeFactory);
|
||||||
|
BindPlacement(context, actualDisplayType, "Content");
|
||||||
|
|
||||||
|
var placementSettings = new List<DriverResultPlacement>();
|
||||||
|
|
||||||
|
_contentPartDrivers.Invoke(driver => {
|
||||||
|
var result = driver.BuildDisplay(context);
|
||||||
|
if (result != null) {
|
||||||
|
placementSettings.AddRange(ExtractPlacement(result, context));
|
||||||
|
}
|
||||||
|
}, Logger);
|
||||||
|
|
||||||
|
_contentFieldDrivers.Invoke(driver => {
|
||||||
|
var result = driver.BuildDisplayShape(context);
|
||||||
|
if (result != null) {
|
||||||
|
placementSettings.AddRange(ExtractPlacement(result, context));
|
||||||
|
}
|
||||||
|
}, Logger);
|
||||||
|
|
||||||
|
foreach (var placementSetting in placementSettings) {
|
||||||
|
yield return placementSetting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DriverResultPlacement> GetEditorPlacement(string contentType) {
|
||||||
|
var content = _contentManager.New(contentType);
|
||||||
|
|
||||||
|
dynamic itemShape = CreateItemShape("Content_Edit");
|
||||||
|
itemShape.ContentItem = content;
|
||||||
|
|
||||||
|
var context = new BuildEditorContext(itemShape, content, String.Empty, _shapeFactory);
|
||||||
|
BindPlacement(context, null, "Content");
|
||||||
|
|
||||||
|
var placementSettings = new List<DriverResultPlacement>();
|
||||||
|
|
||||||
|
_contentPartDrivers.Invoke(driver => {
|
||||||
|
var result = driver.BuildEditor(context);
|
||||||
|
if (result != null) {
|
||||||
|
placementSettings.AddRange(ExtractPlacement(result, context));
|
||||||
|
}
|
||||||
|
}, Logger);
|
||||||
|
|
||||||
|
_contentFieldDrivers.Invoke(driver => {
|
||||||
|
var result = driver.BuildEditorShape(context);
|
||||||
|
if (result != null) {
|
||||||
|
placementSettings.AddRange(ExtractPlacement(result, context));
|
||||||
|
}
|
||||||
|
}, Logger);
|
||||||
|
|
||||||
|
foreach (var placementSetting in placementSettings) {
|
||||||
|
yield return placementSetting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> GetZones() {
|
||||||
|
var theme = _siteThemeService.GetSiteTheme();
|
||||||
|
IEnumerable<string> zones = new List<string>();
|
||||||
|
|
||||||
|
// get the zones for this theme
|
||||||
|
if (theme.Zones != null)
|
||||||
|
zones = theme.Zones.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(x => x.Trim())
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// if this theme has no zones defined then walk the BaseTheme chain until we hit a theme which defines zones
|
||||||
|
while (!zones.Any() && theme != null && !string.IsNullOrWhiteSpace(theme.BaseTheme)) {
|
||||||
|
string baseTheme = theme.BaseTheme;
|
||||||
|
theme = _extensionManager.GetExtension(baseTheme);
|
||||||
|
if (theme != null && theme.Zones != null)
|
||||||
|
zones = theme.Zones.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(x => x.Trim())
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return zones;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<DriverResultPlacement> ExtractPlacement(DriverResult result, BuildShapeContext context) {
|
||||||
|
if (result is CombinedResult) {
|
||||||
|
foreach (var subResult in ((CombinedResult) result).GetResults()) {
|
||||||
|
foreach (var placement in ExtractPlacement(subResult, context)) {
|
||||||
|
yield return placement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (result is ContentShapeResult) {
|
||||||
|
var contentShapeResult = (ContentShapeResult) result;
|
||||||
|
|
||||||
|
var placement = context.FindPlacement(
|
||||||
|
contentShapeResult.GetShapeType(),
|
||||||
|
contentShapeResult.GetDifferentiator(),
|
||||||
|
contentShapeResult.GetLocation()
|
||||||
|
);
|
||||||
|
|
||||||
|
string zone = placement.Location;
|
||||||
|
string position = String.Empty;
|
||||||
|
|
||||||
|
// if no placement is found, it's hidden, e.g., no placement was found for the specific ContentType/DisplayType
|
||||||
|
if (placement.Location != null) {
|
||||||
|
var delimiterIndex = placement.Location.IndexOf(':');
|
||||||
|
if (delimiterIndex >= 0) {
|
||||||
|
zone = placement.Location.Substring(0, delimiterIndex);
|
||||||
|
position = placement.Location.Substring(delimiterIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = _contentManager.New(context.ContentItem.ContentType);
|
||||||
|
|
||||||
|
dynamic itemShape = CreateItemShape("Content_Edit");
|
||||||
|
itemShape.ContentItem = content;
|
||||||
|
|
||||||
|
if(context is BuildDisplayContext) {
|
||||||
|
var newContext = new BuildDisplayContext(itemShape, content, "Detail", "", context.New);
|
||||||
|
BindPlacement(newContext, "Detail", "Content");
|
||||||
|
contentShapeResult.Apply(newContext);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var newContext = new BuildEditorContext(itemShape, content, "", context.New);
|
||||||
|
BindPlacement(newContext, null, "Content");
|
||||||
|
contentShapeResult.Apply(newContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
yield return new DriverResultPlacement {
|
||||||
|
Shape = itemShape.Content,
|
||||||
|
ShapeResult = contentShapeResult,
|
||||||
|
PlacementSettings = new PlacementSettings {
|
||||||
|
ShapeType = contentShapeResult.GetShapeType(),
|
||||||
|
Zone = zone,
|
||||||
|
Position = position,
|
||||||
|
Differentiator = contentShapeResult.GetDifferentiator() ?? String.Empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private dynamic CreateItemShape(string actualShapeType) {
|
||||||
|
var zoneHoldingBehavior = new ZoneHoldingBehavior((Func<dynamic>)(() => _shapeFactory.Create("ContentZone", Arguments.Empty())), _workContextAccessor.GetContext().Layout);
|
||||||
|
return _shapeFactory.Create(actualShapeType, Arguments.Empty(), new[] { zoneHoldingBehavior });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindPlacement(BuildShapeContext context, string displayType, string stereotype) {
|
||||||
|
context.FindPlacement = (partShapeType, differentiator, defaultLocation) => {
|
||||||
|
|
||||||
|
var theme = _siteThemeService.GetSiteTheme();
|
||||||
|
var shapeTable = _shapeTableLocator.Lookup(theme.Id);
|
||||||
|
|
||||||
|
var request = _requestContext.HttpContext.Request;
|
||||||
|
|
||||||
|
ShapeDescriptor descriptor;
|
||||||
|
if (shapeTable.Descriptors.TryGetValue(partShapeType, out descriptor)) {
|
||||||
|
var placementContext = new ShapePlacementContext {
|
||||||
|
ContentType = context.ContentItem.ContentType,
|
||||||
|
Stereotype = stereotype,
|
||||||
|
DisplayType = displayType,
|
||||||
|
Differentiator = differentiator,
|
||||||
|
Path = VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(request.Path)) // get the current app-relative path, i.e. ~/my-blog/foo
|
||||||
|
};
|
||||||
|
|
||||||
|
// define which location should be used if none placement is hit
|
||||||
|
descriptor.DefaultPlacement = defaultLocation;
|
||||||
|
|
||||||
|
var placement = descriptor.Placement(placementContext);
|
||||||
|
if (placement != null) {
|
||||||
|
placement.Source = placementContext.Source;
|
||||||
|
return placement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PlacementInfo {
|
||||||
|
Location = defaultLocation,
|
||||||
|
Source = String.Empty
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Orchard.ContentTypes.Settings {
|
||||||
|
public class PlacementSettings : IEquatable<PlacementSettings> {
|
||||||
|
/// <summary>
|
||||||
|
/// e.g., Parts_Title_Summary
|
||||||
|
/// </summary>
|
||||||
|
public string ShapeType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// e.g., Header, /Navigation
|
||||||
|
/// </summary>
|
||||||
|
public string Zone { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// e.g, 5, after.7
|
||||||
|
/// </summary>
|
||||||
|
public string Position { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// e.g, 5, MyTextField
|
||||||
|
/// </summary>
|
||||||
|
public string Differentiator { get; set; }
|
||||||
|
|
||||||
|
public bool IsSameAs(PlacementSettings other) {
|
||||||
|
return (ShapeType ?? String.Empty) == (other.ShapeType ?? String.Empty)
|
||||||
|
&& (Differentiator ?? String.Empty) == (other.Differentiator ?? String.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(PlacementSettings other) {
|
||||||
|
if(other == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ShapeType ?? String.Empty) == (other.ShapeType ?? String.Empty)
|
||||||
|
&& (Zone ?? String.Empty) == (other.Zone ?? String.Empty)
|
||||||
|
&& (Position ?? String.Empty) == (other.Position ?? String.Empty)
|
||||||
|
&& (Differentiator ?? String.Empty) == (other.Differentiator ?? String.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 897 B |
@@ -109,4 +109,40 @@ fieldset.action {
|
|||||||
.manage-part dd dd {
|
.manage-part dd dd {
|
||||||
float:left;
|
float:left;
|
||||||
padding-left:.5em;
|
padding-left:.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* PLACEMENT EDITOR */
|
||||||
|
|
||||||
|
#placement li {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 0px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placement li .shape-type {
|
||||||
|
cursor: move;
|
||||||
|
background-color: #eee;
|
||||||
|
background: #EEE url(images/move.gif) no-repeat 10px 15px;
|
||||||
|
height: 30px;
|
||||||
|
padding: 10px 0px 0px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placement li .shape-editor {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#save-message {
|
||||||
|
display: none;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay{
|
||||||
|
background:red repeat top left;
|
||||||
|
position:fixed;
|
||||||
|
top:0px;
|
||||||
|
bottom:0px;
|
||||||
|
left:0px;
|
||||||
|
right:0px;
|
||||||
|
z-index:100;
|
||||||
}
|
}
|
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
|
using Orchard.ContentTypes.Services;
|
||||||
|
using Orchard.ContentTypes.Settings;
|
||||||
|
|
||||||
|
namespace Orchard.ContentTypes.ViewModels {
|
||||||
|
public class EditPlacementViewModel {
|
||||||
|
public ContentTypeDefinition ContentTypeDefinition { get; set; }
|
||||||
|
public PlacementSettings[] PlacementSettings { get; set; }
|
||||||
|
public List<DriverResultPlacement> AllPlacements { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Orchard.ContentManagement.MetaData.Models;
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
using Orchard.ContentManagement.ViewModels;
|
using Orchard.ContentManagement.ViewModels;
|
||||||
|
@@ -2,12 +2,15 @@
|
|||||||
@{
|
@{
|
||||||
Style.Require("ContentTypesAdmin");
|
Style.Require("ContentTypesAdmin");
|
||||||
Script.Require("jQuery");
|
Script.Require("jQuery");
|
||||||
Layout.Title = T("Edit Content Type").ToString();
|
Layout.Title = T("Edit Content Type - {0}", Model.DisplayName).ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@using (Html.BeginFormAntiForgeryPost()) {
|
@using (Html.BeginFormAntiForgeryPost()) {
|
||||||
// todo: come up with real itemtype definitions and locations for said definitions
|
// todo: come up with real itemtype definitions and locations for said definitions
|
||||||
<div itemscope="itemscope" itemid="@Model.Name" itemtype="http://orchardproject.net/data/ContentType">
|
<div itemscope="itemscope" itemid="@Model.Name" itemtype="http://orchardproject.net/data/ContentType">
|
||||||
|
<div class="manage add-to-type">
|
||||||
|
@Html.ActionLink(T("Edit Placement").Text, "EditPlacement", new { area = "Orchard.ContentTypes", id = Model.Name }, new { @class = "button" })
|
||||||
|
</div>
|
||||||
@Html.ValidationSummary()
|
@Html.ValidationSummary()
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="DisplayName">@T("Display Name")</label>
|
<label for="DisplayName">@T("Display Name")</label>
|
||||||
@@ -19,7 +22,7 @@
|
|||||||
<meta itemprop="Id" content="@Model.Name" />
|
<meta itemprop="Id" content="@Model.Name" />
|
||||||
@Html.HiddenFor(m => m.Name)
|
@Html.HiddenFor(m => m.Name)
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@{ Html.RenderTemplates(Model.Templates); }
|
@{ Html.RenderTemplates(Model.Templates); }
|
||||||
<div class="manage-type">
|
<div class="manage-type">
|
||||||
<h2>@T("Fields")</h2>
|
<h2>@T("Fields")</h2>
|
||||||
<div class="manage add-to-type">
|
<div class="manage add-to-type">
|
||||||
@@ -31,6 +34,8 @@
|
|||||||
@Html.ActionLink(T("Add Parts").Text, "AddPartsTo", new { area = "Orchard.ContentTypes", id = Model.Name }, new { @class = "button" })
|
@Html.ActionLink(T("Add Parts").Text, "AddPartsTo", new { area = "Orchard.ContentTypes", id = Model.Name }, new { @class = "button" })
|
||||||
</div>
|
</div>
|
||||||
@Html.EditorFor(m => m.Parts, "TypeParts", "")
|
@Html.EditorFor(m => m.Parts, "TypeParts", "")
|
||||||
|
<h2>@T("Placement")</h2>
|
||||||
|
@Html.EditorFor(m => m.Settings, "Placement", "")
|
||||||
</div>
|
</div>
|
||||||
<fieldset class="action">
|
<fieldset class="action">
|
||||||
<button class="primaryAction" type="submit" name="submit.Save" value="Save">@T("Save")</button>
|
<button class="primaryAction" type="submit" name="submit.Save" value="Save">@T("Save")</button>
|
||||||
|
@@ -0,0 +1,92 @@
|
|||||||
|
@model Orchard.ContentTypes.ViewModels.EditPlacementViewModel
|
||||||
|
@{
|
||||||
|
Style.Require("ContentTypesAdmin");
|
||||||
|
Script.Require("jQueryUI_Sortable");
|
||||||
|
Layout.Title = T("Edit Placement - {0}", Model.ContentTypeDefinition.DisplayName).ToString();
|
||||||
|
|
||||||
|
var hiddenShapes = Model.AllPlacements.Where(x => String.IsNullOrEmpty(x.PlacementSettings.Zone) && (String.IsNullOrWhiteSpace(x.PlacementSettings.Position) || x.PlacementSettings.Position == "-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
<div id="save-message" class="message message-Warning">@T("You need to hit \"Save\" in order to save your changes.")</div>
|
||||||
|
|
||||||
|
@using (Html.BeginFormAntiForgeryPost()) {
|
||||||
|
@Html.ValidationSummary()
|
||||||
|
|
||||||
|
|
||||||
|
<ul id="placement">
|
||||||
|
@for (int i = 0; i < Model.AllPlacements.Count; i++ ) {
|
||||||
|
|
||||||
|
var placement = Model.AllPlacements[i].PlacementSettings;
|
||||||
|
|
||||||
|
<li data-shape-type="@placement.ShapeType" data-shape-differentiator="@placement.Differentiator" data-shape-zone="Content" data-shape-position="@placement.Position">
|
||||||
|
<div class="shape-type"><h3>@placement.ShapeType @placement.Differentiator</h3></div>
|
||||||
|
<div class="shape-editor">@Display(Model.AllPlacements[i].Shape)</div>
|
||||||
|
@* @shape.Position @(Model.PlacementSettings.Any(x => x.Equals(shape)))*@
|
||||||
|
@Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.ShapeType, new { @class = "type" })
|
||||||
|
@Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Differentiator, new { @class = "differentiator" })
|
||||||
|
@Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Zone, new { @class = "zone" })
|
||||||
|
@Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Position, new { @class = "position" })
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<fieldset class="action">
|
||||||
|
<button class="primaryAction" type="submit" name="submit.Save" value="Save">@T("Save")</button>
|
||||||
|
<button class="primaryAction" type="submit" name="submit.Restore" value="Restore" itemprop="RemoveUrl">@T("Restore")</button>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@using (Script.Foot()) {
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
(function ($) {
|
||||||
|
|
||||||
|
var startPos;
|
||||||
|
|
||||||
|
$('#placement').sortable({
|
||||||
|
start: function (event, ui) {
|
||||||
|
var self = $(ui.item);
|
||||||
|
startPos = self.prevAll().size();
|
||||||
|
},
|
||||||
|
stop: function (event, ui) {
|
||||||
|
var self = $(ui.item);
|
||||||
|
var stopPos = self.prevAll().size();
|
||||||
|
|
||||||
|
var begin = Math.min(startPos, stopPos);
|
||||||
|
var end = Math.max(startPos, stopPos);
|
||||||
|
|
||||||
|
// get siblings ( .siblings() doesn't include itself)
|
||||||
|
var siblings = self.parent().children();
|
||||||
|
for (var i = begin; i < end; i++) {
|
||||||
|
// get both positions
|
||||||
|
var a = $(siblings[i]).find('.position').val();
|
||||||
|
var b = $(siblings[i + 1]).find('.position').val();
|
||||||
|
|
||||||
|
// swap values
|
||||||
|
var temp = a;
|
||||||
|
$(siblings[i]).find('.position').val(b);
|
||||||
|
$(siblings[i + 1]).find('.position').val(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure all successive values are different
|
||||||
|
for (var i = 0; i < siblings.size() - 1; i++) {
|
||||||
|
// get both positions
|
||||||
|
a = $(siblings[i]).find('.position').val();
|
||||||
|
b = $(siblings[i + 1]).find('.position').val();
|
||||||
|
|
||||||
|
if (a == b) {
|
||||||
|
$(siblings[i + 1]).find('.position').val(a + '.5');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#save-message').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#placement").disableSelection();
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
}
|
@@ -47,5 +47,9 @@ namespace Orchard.ContentManagement.Drivers {
|
|||||||
result.Apply(context);
|
result.Apply(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DriverResult> GetResults() {
|
||||||
|
return _results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -89,5 +89,21 @@ namespace Orchard.ContentManagement.Drivers {
|
|||||||
_groupId=groupId;
|
_groupId=groupId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetDifferentiator() {
|
||||||
|
return _differentiator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetGroup() {
|
||||||
|
return _groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetLocation() {
|
||||||
|
return _defaultLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetShapeType() {
|
||||||
|
return _shapeType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,7 +4,7 @@ namespace Orchard.ContentManagement.Drivers {
|
|||||||
public class DriverResult {
|
public class DriverResult {
|
||||||
public virtual void Apply(BuildDisplayContext context) { }
|
public virtual void Apply(BuildDisplayContext context) { }
|
||||||
public virtual void Apply(BuildEditorContext context) { }
|
public virtual void Apply(BuildEditorContext context) { }
|
||||||
|
|
||||||
public ContentPart ContentPart { get; set; }
|
public ContentPart ContentPart { get; set; }
|
||||||
public ContentField ContentField { get; set; }
|
public ContentField ContentField { get; set; }
|
||||||
}
|
}
|
||||||
|
@@ -16,15 +16,19 @@ namespace Orchard.DisplayManagement.Descriptors {
|
|||||||
private readonly IExtensionManager _extensionManager;
|
private readonly IExtensionManager _extensionManager;
|
||||||
private readonly ICacheManager _cacheManager;
|
private readonly ICacheManager _cacheManager;
|
||||||
private readonly IParallelCacheContext _parallelCacheContext;
|
private readonly IParallelCacheContext _parallelCacheContext;
|
||||||
|
private readonly IEnumerable<IShapeTableEventHandler> _shapeTableEventHandlers;
|
||||||
|
|
||||||
public DefaultShapeTableManager(
|
public DefaultShapeTableManager(
|
||||||
IEnumerable<Meta<IShapeTableProvider>> bindingStrategies,
|
IEnumerable<Meta<IShapeTableProvider>> bindingStrategies,
|
||||||
IExtensionManager extensionManager,
|
IExtensionManager extensionManager,
|
||||||
ICacheManager cacheManager,
|
ICacheManager cacheManager,
|
||||||
IParallelCacheContext parallelCacheContext) {
|
IParallelCacheContext parallelCacheContext,
|
||||||
|
IEnumerable<IShapeTableEventHandler> shapeTableEventHandlers
|
||||||
|
) {
|
||||||
_extensionManager = extensionManager;
|
_extensionManager = extensionManager;
|
||||||
_cacheManager = cacheManager;
|
_cacheManager = cacheManager;
|
||||||
_parallelCacheContext = parallelCacheContext;
|
_parallelCacheContext = parallelCacheContext;
|
||||||
|
_shapeTableEventHandlers = shapeTableEventHandlers;
|
||||||
_bindingStrategies = bindingStrategies;
|
_bindingStrategies = bindingStrategies;
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
@@ -72,6 +76,8 @@ namespace Orchard.DisplayManagement.Descriptors {
|
|||||||
Bindings = descriptors.SelectMany(sd => sd.Bindings).ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase),
|
Bindings = descriptors.SelectMany(sd => sd.Bindings).ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_shapeTableEventHandlers.Invoke(ctx => ctx.ShapeTableCreated(result), Logger);
|
||||||
|
|
||||||
Logger.Information("Done building shape table");
|
Logger.Information("Done building shape table");
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
namespace Orchard.DisplayManagement.Descriptors {
|
using Orchard.Events;
|
||||||
|
|
||||||
|
namespace Orchard.DisplayManagement.Descriptors {
|
||||||
|
|
||||||
public interface IShapeTableManager : ISingletonDependency {
|
public interface IShapeTableManager : ISingletonDependency {
|
||||||
ShapeTable GetShapeTable(string themeName);
|
ShapeTable GetShapeTable(string themeName);
|
||||||
@@ -7,4 +9,9 @@
|
|||||||
public interface IShapeTableProvider : IDependency {
|
public interface IShapeTableProvider : IDependency {
|
||||||
void Discover(ShapeTableBuilder builder);
|
void Discover(ShapeTableBuilder builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IShapeTableEventHandler : IEventHandler {
|
||||||
|
void ShapeTableCreated(ShapeTable shapeTable);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -103,7 +103,7 @@ namespace Orchard.DisplayManagement.Descriptors {
|
|||||||
descriptor.Placement = ctx => predicate(ctx) ? location : next(ctx);
|
descriptor.Placement = ctx => predicate(ctx) ? location : next(ctx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShapeAlteration Build() {
|
public ShapeAlteration Build() {
|
||||||
return new ShapeAlteration(_shapeType, _feature, _configurations.ToArray());
|
return new ShapeAlteration(_shapeType, _feature, _configurations.ToArray());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user