Skip to content

Commit

Permalink
Update placement GUI.
Browse files Browse the repository at this point in the history
  • Loading branch information
microposmp committed Dec 6, 2020
1 parent 59e76d2 commit 84df060
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OrchardCore.DisplayManagement;
using OrchardCore.DisplayManagement.Descriptors.ShapePlacementStrategy;
using OrchardCore.DisplayManagement.Notify;
using OrchardCore.Navigation;
using OrchardCore.Placements.Services;
using OrchardCore.Placements.ViewModels;
using OrchardCore.Routing;
using OrchardCore.Settings;

namespace OrchardCore.Placements.Controllers
{
Expand All @@ -24,43 +28,75 @@ public class AdminController : Controller
private readonly IHtmlLocalizer H;
private readonly IStringLocalizer S;
private readonly INotifier _notifier;
private readonly ISiteService _siteService;
private readonly dynamic New;

public AdminController(
ILogger<AdminController> logger,
IAuthorizationService authorizationService,
PlacementsManager placementsManager,
IHtmlLocalizer<AdminController> htmlLocalizer,
IStringLocalizer<AdminController> stringLocalizer,
INotifier notifier)
INotifier notifier,
ISiteService siteService,
IShapeFactory shapeFactory)
{
_logger = logger;
_authorizationService = authorizationService;
_placementsManager = placementsManager;
_notifier = notifier;
_siteService = siteService;

New = shapeFactory;
H = htmlLocalizer;
S = stringLocalizer;
}

public async Task<IActionResult> Index()
public async Task<IActionResult> Index(ContentOptions options, PagerParameters pagerParameters)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements))
{
return Forbid();
}

var siteSettings = await _siteService.GetSiteSettingsAsync();
var pager = new Pager(pagerParameters, siteSettings.PageSize);

var shapeTypes = await _placementsManager.ListShapePlacementsAsync();

return View(new ListShapePlacementsViewModel
var shapeList = shapeTypes.Select(entry => new ShapePlacementViewModel
{
ShapePlacements = shapeTypes.Select(entry => new ShapePlacementViewModel
{
ShapeType = entry.Key
})
});
ShapeType = entry.Key
}).ToList();

if (!string.IsNullOrWhiteSpace(options.Search))
{
shapeList = shapeList.Where(x => x.ShapeType.Contains(options.Search)).ToList();
}

var count = shapeList.Count();

shapeList = shapeList.OrderBy(x => x.ShapeType)
.Skip(pager.GetStartIndex())
.Take(pager.PageSize).ToList();

var pagerShape = (await New.Pager(pager)).TotalItemCount(count);

var model = new ListShapePlacementsViewModel
{
ShapePlacements = shapeList,
Pager = pagerShape,
Options = options,
};

model.Options.ContentsBulkAction = new List<SelectListItem>() {
new SelectListItem() { Text = S["Delete"], Value = nameof(ContentsBulkAction.Remove) }
};

return View("Index", model);
}

public async Task<IActionResult> Create(string suggestion, string returnUrl = null)
public async Task<IActionResult> Create(string suggestion)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements))
{
Expand All @@ -76,58 +112,35 @@ public async Task<IActionResult> Create(string suggestion, string returnUrl = nu
Nodes = JsonConvert.SerializeObject(template, Formatting.Indented)
};

ViewData["ReturnUrl"] = returnUrl;
return View("Edit", viewModel);
}

public async Task<IActionResult> Edit(string shapeType, string displayType = null, string contentType = null, string contentPart = null, string differentiator = null, string returnUrl = null)
public async Task<IActionResult> Edit(string name)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements))
{
return Forbid();
}

var placementNodes = (await _placementsManager.GetShapePlacementsAsync(shapeType))?.ToList() ?? new List<PlacementNode>();

if (!placementNodes.Any() || ShouldCreateNode(placementNodes, displayType, contentType, contentPart, differentiator))
{
var generatedNode = new PlacementNode
{
DisplayType = displayType,
Differentiator = differentiator
};
if (!string.IsNullOrEmpty(contentType))
{
generatedNode.Filters.Add("contentType", new JArray(contentType));
}
if (!string.IsNullOrEmpty(contentPart))
{
generatedNode.Filters.Add("contentPart", new JArray(contentPart));
}

placementNodes.Add(generatedNode);
}
var placementNodes = (await _placementsManager.GetShapePlacementsAsync(name))?.ToList() ?? new List<PlacementNode>();

var viewModel = new EditShapePlacementViewModel
{
ShapeType = shapeType,
ShapeType = name,
Nodes = JsonConvert.SerializeObject(placementNodes, Formatting.Indented)
};

ViewData["ReturnUrl"] = returnUrl;
return View(viewModel);
}

[HttpPost, ActionName("Edit")]
public async Task<IActionResult> Edit(EditShapePlacementViewModel viewModel, string submit, string returnUrl = null)
public async Task<IActionResult> Edit(EditShapePlacementViewModel viewModel, string submit)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements))
{
return Forbid();
}

ViewData["ReturnUrl"] = returnUrl;

if (viewModel.Creating && await _placementsManager.GetShapePlacementsAsync(viewModel.ShapeType) != null)
{
// Prevent overriding existing rules on creation
Expand All @@ -139,9 +152,6 @@ public async Task<IActionResult> Edit(EditShapePlacementViewModel viewModel, str
{
IEnumerable<PlacementNode> placementNodes = JsonConvert.DeserializeObject<PlacementNode[]>(viewModel.Nodes) ?? new PlacementNode[0];

// Remove empty nodes
placementNodes = placementNodes.Where(node => !IsEmpty(node));

if (placementNodes.Any())
{
// Save
Expand Down Expand Up @@ -174,75 +184,58 @@ public async Task<IActionResult> Edit(EditShapePlacementViewModel viewModel, str
return View(viewModel);
}

if (submit != "SaveAndContinue")
if (submit == "SaveAndContinue")
{
return RedirectToReturnUrlOrIndex(returnUrl);
return RedirectToAction(nameof(Edit), new { name = viewModel.ShapeType });
}
else
{
return RedirectToAction(nameof(Index));
}

return View(viewModel);
}

[HttpPost, ActionName("Delete")]
public async Task<IActionResult> Delete(string shapeType, string returnUrl = null)
public async Task<IActionResult> Delete(string name)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements))
{
return Forbid();
}

await _placementsManager.RemoveShapePlacementsAsync(shapeType);
_notifier.Success(H["The \"{0}\" placement has been deleted.", shapeType]);
await _placementsManager.RemoveShapePlacementsAsync(name);
_notifier.Success(H["The \"{0}\" placement has been deleted.", name]);

return RedirectToReturnUrlOrIndex(returnUrl);
return RedirectToAction(nameof(Index));
}

private IActionResult RedirectToReturnUrlOrIndex(string returnUrl)
[HttpPost, ActionName("Index")]
[FormValueRequired("submit.BulkAction")]
public async Task<ActionResult> IndexPost(ViewModels.ContentOptions options, IEnumerable<string> itemIds)
{
if ((String.IsNullOrEmpty(returnUrl) == false) && (Url.IsLocalUrl(returnUrl)))
{
return Redirect(returnUrl);
}
else
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements))
{
return RedirectToAction(nameof(Index));
return Forbid();
}
}

private static bool ShouldCreateNode(IEnumerable<PlacementNode> nodes, string displayType, string contentType, string contentPart, string differentiator)
{
if (string.IsNullOrEmpty(displayType) && string.IsNullOrEmpty(differentiator))
if (itemIds?.Count() > 0)
{
return false;
}
else
{
return !nodes.Any(node =>
(string.IsNullOrEmpty(displayType) || node.DisplayType == displayType) &&
(string.IsNullOrEmpty(contentType) || (node.Filters.ContainsKey("contentType") && FilterEquals(node.Filters["contentType"], contentType))) &&
(string.IsNullOrEmpty(contentPart) || (node.Filters.ContainsKey("contentPart") && FilterEquals(node.Filters["contentPart"], contentPart))) &&
(string.IsNullOrEmpty(differentiator) || node.Differentiator == differentiator));
switch (options.BulkAction)
{
case ContentsBulkAction.None:
break;
case ContentsBulkAction.Remove:
foreach (var item in itemIds)
{
await _placementsManager.RemoveShapePlacementsAsync(item);
}
_notifier.Success(H["Placements successfully removed."]);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}

private static bool IsEmpty(PlacementNode node)
{
return string.IsNullOrEmpty(node.Location)
&& string.IsNullOrEmpty(node.ShapeType)
&& (node.Alternates == null || node.Alternates.Length == 0)
&& (node.Wrappers == null || node.Wrappers.Length == 0);
}

private static bool FilterEquals(JToken token, string value)
{
if (token is JArray)
{
var tokenValues = token.Values<string>();
return tokenValues.Count() == 1 && tokenValues.First() == value;
}
else
{
return token.Value<string>() == value;
}
return RedirectToAction("Index");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace OrchardCore.Placements.ViewModels
{
public class ListShapePlacementsViewModel
{
public IEnumerable<ShapePlacementViewModel> ShapePlacements { get; set; }
public IList<ShapePlacementViewModel> ShapePlacements { get; set; }
public dynamic Pager { get; set; }
public ContentOptions Options { get; set; } = new ContentOptions();
}

public class ContentOptions
{
public string Search { get; set; }
public ContentsBulkAction BulkAction { get; set; }

#region Lists to populate

[BindNever]
public List<SelectListItem> ContentsBulkAction { get; set; }

#endregion Lists to populate
}

public enum ContentsBulkAction
{
None,
Remove
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
@model EditShapePlacementViewModel
@{
var returnUrl = ViewData["returnUrl"]?.ToString();
}

<style asp-name="codemirror"></style>
<script asp-name="codemirror" depends-on="admin" at="Foot"></script>
Expand All @@ -11,7 +8,7 @@

<zone Name="Title"><h1>@RenderTitleSegments(Model.Creating ? T["Create Placement"] : T["Edit Placement"])</h1></zone>

<form asp-action="Edit" asp-route-returnUrl="@ViewData["returnUrl"]" method="post">
<form asp-action="Edit" method="post">
@Html.HiddenFor(m => m.Creating)
@if (!Model.Creating)
{
Expand Down Expand Up @@ -41,15 +38,7 @@
</div>
</div>

@if (!Model.Creating)
{
<a asp-route-action="Delete" asp-route-area="OrchardCore.Placements" asp-route-shapeType="@Model.ShapeType" class="btn btn-danger" role="button" itemprop="UnsafeUrl RemoveUrl">@T["Delete"]</a>
}

@if (Url.IsLocalUrl(returnUrl))
{
<a class="btn btn-secondary" href="@returnUrl">@T["Cancel"]</a>
}
<a class="btn btn-secondary cancel" role="button" asp-route-action="Index">@T["Cancel"]</a>
</div>
</form>

Expand Down
Loading

0 comments on commit 84df060

Please sign in to comment.