From 90c16e0274c1be1a770b1e92a77d58886c46aa35 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Tue, 15 Mar 2011 15:10:24 -0700 Subject: [PATCH] More progress on the next rev of the global widget management UI. Starting to come together. Widgets can be added once again. --HG-- branch : dev --- .../Commands/WidgetCommands.cs | 6 +- .../Controllers/AdminController.cs | 88 +++++++++++-------- .../Orchard.Widgets/Orchard.Widgets.csproj | 3 + .../Services/IWidgetsService.cs | 6 +- .../Services/WidgetsService.cs | 14 ++- .../Styles/orchard-widgets-admin.css | 34 ++++++- .../Views/Admin/ChooseWidget.cshtml | 27 ++++++ .../Orchard.Widgets/Views/Admin/Index.cshtml | 8 +- 8 files changed, 135 insertions(+), 51 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/ChooseWidget.cshtml diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Commands/WidgetCommands.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Commands/WidgetCommands.cs index 30593283f..184b45e8e 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Commands/WidgetCommands.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Commands/WidgetCommands.cs @@ -50,11 +50,11 @@ namespace Orchard.Widgets.Commands { [CommandHelp("widget create /Title: /Zone:<zone> /Position:<position> /Layer:<layer> [/Owner:<owner>] [/Text:<text>] [/UseLoremIpsumText:true|false]\r\n\t" + "Creates a new widget")] [OrchardSwitches("Title,Zone,Position,Layer,Owner,Text,UseLoremIpsumText")] public void Create(string type) { - var widgetTypes = _widgetsService.GetWidgetTypes(); - if (!widgetTypes.Contains(type)) { + var widgetTypeNames = _widgetsService.GetWidgetTypeNames(); + if (!widgetTypeNames.Contains(type)) { throw new OrchardException(T("Creating widget failed : type {0} was not found. Supported widget types are: {1}.", type, - widgetTypes.Aggregate(String.Empty, (current, widgetType) => current + " " + widgetType))); + widgetTypeNames.Aggregate(String.Empty, (current, widgetType) => current + " " + widgetType))); } var layer = GetLayer(Layer); diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs index 4e07ef598..d6f478dca 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs @@ -44,42 +44,24 @@ namespace Orchard.Widgets.Controllers { public ActionResult Index(int? layerId) { IEnumerable<LayerPart> layers = _widgetsService.GetLayers(); - LayerPart currentLayer; - IEnumerable<WidgetPart> widgets; - - if (layers.Count() > 0) { - currentLayer = layerId == null ? - layers.First() : - layers.FirstOrDefault(layer => layer.Id == layerId); - - if (currentLayer == null && - layerId != null) { - // Incorrect layer id passed - Services.Notifier.Error(T("Layer not found: {0}", layerId)); - return RedirectToAction("Index"); - } - - widgets = _widgetsService.GetWidgets(); - } - else { - currentLayer = null; - widgets = new List<WidgetPart>(); + if (layers.Count() == 0) { + Services.Notifier.Error(T("Layer not found: {0}", layerId)); + return RedirectToAction("Index"); } - //WidgetsIndexViewModel widgetsIndexViewModel = new WidgetsIndexViewModel { - // WidgetTypes = _widgetsService.GetWidgetTypes(), - // Layers = layers, - // Zones = _widgetsService.GetZones(), - // CurrentLayer = currentLayer, - // CurrentLayerWidgets = currentLayerWidgets - //}; + LayerPart currentLayer = layerId == null + ? layers.First() + : layers.FirstOrDefault(layer => layer.Id == layerId); - //return View(widgetsIndexViewModel); + if (currentLayer == null && layerId != null) { // Incorrect layer id passed + Services.Notifier.Error(T("Layer not found: {0}", layerId)); + return RedirectToAction("Index"); + } dynamic viewModel = Shape.ViewModel() .CurrentLayer(currentLayer) .Layers(layers) - .Widgets(widgets) + .Widgets(_widgetsService.GetWidgets()) .Zones(_widgetsService.GetZones()); // Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation. @@ -114,7 +96,42 @@ namespace Orchard.Widgets.Controllers { return this.RedirectLocal(returnUrl, () => RedirectToAction("Index")); } - public ActionResult AddWidget(int layerId, string widgetType) { + public ActionResult ChooseWidget(int layerId, string zone, string returnUrl) { + if (!Services.Authorizer.Authorize(Permissions.ManageWidgets, T(NotAuthorizedManageWidgetsLabel))) + return new HttpUnauthorizedResult(); + + if (string.IsNullOrWhiteSpace(zone)) { + Services.Notifier.Error(T("Need a zone specified for widget placement.")); + return RedirectToAction("Index"); + } + + IEnumerable<LayerPart> layers = _widgetsService.GetLayers(); + + if (layers.Count() == 0) { + Services.Notifier.Error(T("Layer not found: {0}", layerId)); + return RedirectToAction("Index"); + } + + LayerPart currentLayer = layerId == null + ? layers.First() + : layers.FirstOrDefault(layer => layer.Id == layerId); + + if (currentLayer == null && layerId != null) { // Incorrect layer id passed + Services.Notifier.Error(T("Layer not found: {0}", layerId)); + return RedirectToAction("Index"); + } + + dynamic viewModel = Shape.ViewModel() + .CurrentLayer(currentLayer) + .Zone(zone) + .WidgetTypes(_widgetsService.GetWidgetTypes()) + .ReturnUrl(returnUrl); + + // Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation. + return View((object)viewModel); + } + + public ActionResult AddWidget(int layerId, string widgetType, string zone, string returnUrl) { if (!Services.Authorizer.Authorize(Permissions.ManageWidgets, T(NotAuthorizedManageWidgetsLabel))) return new HttpUnauthorizedResult(); @@ -125,7 +142,7 @@ namespace Orchard.Widgets.Controllers { int widgetPosition = _widgetsService.GetWidgets(layerId).Count() + 1; widgetPart.Position = widgetPosition.ToString(); - + widgetPart.Zone = zone; widgetPart.LayerPart = _widgetsService.GetLayer(layerId); dynamic model = Services.ContentManager.BuildEditor(widgetPart); // Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation. @@ -133,13 +150,12 @@ namespace Orchard.Widgets.Controllers { } catch (Exception exception) { this.Error(exception, T("Creating widget failed: {0}", exception.Message), Logger, Services.Notifier); - - return RedirectToAction("Index", "Admin", new { id = layerId }); + return this.RedirectLocal(returnUrl, () => RedirectToAction("Index")); } } [HttpPost, ActionName("AddWidget")] - public ActionResult AddWidgetPOST(int layerId, string widgetType) { + public ActionResult AddWidgetPOST(int layerId, string widgetType, string returnUrl) { if (!Services.Authorizer.Authorize(Permissions.ManageWidgets, T(NotAuthorizedManageWidgetsLabel))) return new HttpUnauthorizedResult(); @@ -155,12 +171,12 @@ namespace Orchard.Widgets.Controllers { return View((object)model); } - Services.Notifier.Information(T("Your {0} has been created.", widgetPart.TypeDefinition.DisplayName)); + Services.Notifier.Information(T("Your {0} has been added.", widgetPart.TypeDefinition.DisplayName)); } catch (Exception exception) { this.Error(exception, T("Creating widget failed: {0}", exception.Message), Logger, Services.Notifier); } - return RedirectToAction("Index", "Admin", new { id = layerId }); + return this.RedirectLocal(returnUrl, () => RedirectToAction("Index")); } public ActionResult AddLayer() { diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj b/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj index 8c184261f..001ef0030 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj @@ -139,6 +139,9 @@ <ItemGroup> <Content Include="web.config" /> </ItemGroup> + <ItemGroup> + <Content Include="Views\Admin\ChooseWidget.cshtml" /> + </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.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. diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Services/IWidgetsService.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Services/IWidgetsService.cs index 966504a55..4519c7c78 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Services/IWidgetsService.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Services/IWidgetsService.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Orchard.Widgets.Models; namespace Orchard.Widgets.Services { @@ -8,7 +9,8 @@ namespace Orchard.Widgets.Services { IEnumerable<LayerPart> GetLayers(); - IEnumerable<string> GetWidgetTypes(); + IEnumerable<Tuple<string, string>> GetWidgetTypes(); + IEnumerable<string> GetWidgetTypeNames(); IEnumerable<WidgetPart> GetWidgets(); IEnumerable<WidgetPart> GetWidgets(int layerId); diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Services/WidgetsService.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Services/WidgetsService.cs index 77e1dfcef..943ebd451 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Services/WidgetsService.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Services/WidgetsService.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Orchard.ContentManagement; @@ -22,10 +23,17 @@ namespace Orchard.Widgets.Services { _featureManager = featureManager; } - public IEnumerable<string> GetWidgetTypes() { + public IEnumerable<Tuple<string, string>> GetWidgetTypes() { return _contentManager.GetContentTypeDefinitions() .Where(contentTypeDefinition => contentTypeDefinition.Settings.ContainsKey("Stereotype") && contentTypeDefinition.Settings["Stereotype"] == "Widget") - .Select(contentTypeDefinition => contentTypeDefinition.Name); + .Select(contentTypeDefinition => + Tuple.Create( + contentTypeDefinition.Name, + contentTypeDefinition.Settings.ContainsKey("Description") ? contentTypeDefinition.Settings["Description"] : null)); + } + + public IEnumerable<string> GetWidgetTypeNames() { + return GetWidgetTypes().Select(type => type.Item1); } public IEnumerable<LayerPart> GetLayers() { diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Styles/orchard-widgets-admin.css b/src/Orchard.Web/Modules/Orchard.Widgets/Styles/orchard-widgets-admin.css index 73f60200a..44151e1cf 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Styles/orchard-widgets-admin.css +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Styles/orchard-widgets-admin.css @@ -24,7 +24,7 @@ vertical-align:middle; margin-left:10px; } -#widgets-zones { +#widgets-zones, #widgets-available { background:#F3F4F5; border:1px solid #E4E5E6; padding:0 5px; @@ -32,16 +32,23 @@ padding:0 5px; #widgets-zones ol { list-style:decimal inside; } -#widgets-zones li { +#widgets-zones li, #widgets-available li { background:#FFF; color:#AEC3CE; border:1px solid #EAEAEA; margin:5px 0; padding:0 10px; +position:relative; +} +#widgets-zones li:hover { +border-color:#bfd3a7; } #widgets-zones h2 { font-size:1.077em; } +#widgets-available h2 { +font-size:1.231em; +} #widgets-zones h2, #widgets-zones li li { color:#333; } @@ -55,3 +62,26 @@ padding:5px 10px 5px 25px; margin-left:-18px; vertical-align:-2px; } +#widgets-zones .widgets-actions { +position:absolute; +top:5px; +right:10px; +} +#widgets-available li { +border:0; +padding:0; +} +#widgets-available li a { +border:1px solid #EAEAEA; +display:block; +padding:5px 10px; +} +#widgets-available li a:hover { +border-color:#bfd3a7; +} +#widgets-available a h2, #widgets-available a p { +color:#333; +} +#widgets-available a p { +margin-top:5px; +} diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/ChooseWidget.cshtml b/src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/ChooseWidget.cshtml new file mode 100644 index 000000000..f9960e629 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/ChooseWidget.cshtml @@ -0,0 +1,27 @@ +@using Orchard.Utility.Extensions; +@using Orchard.Widgets.Models; +@{ + Style.Require("WidgetsAdmin"); + Layout.Title = T("Choose A Widget").ToString(); + IEnumerable<Tuple<string, string>> widgetTypes = Model.WidgetTypes; +} + +@if (widgetTypes.Count() > 0) { +<ul id="widgets-available"> + @foreach (var widgetType in widgetTypes.OrderBy(type => (string)type.Item1)) { + string name = widgetType.Item1; + string description = widgetType.Item2; + <li> + <a href="@Url.Action("AddWidget", "Admin", new { area = "Orchard.Widgets", layerId = Model.CurrentLayer.Id, widgetType = name, zone = Model.Zone, returnUrl = Model.ReturnUrl })"> + <h2>@name.CamelFriendly()</h2> + @if (!string.IsNullOrWhiteSpace(description)) { + <p>@description</p> + } + </a> + </li> + } +</ul> +} +else { +<p>@T("There are no widgets available to add.")</p> +} diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/Index.cshtml index 9f04734f9..db91391a7 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Views/Admin/Index.cshtml @@ -35,8 +35,9 @@ @foreach (string zone in zones) { <li> <h2>@zone</h2> + <div class="widgets-actions">@Html.ActionLink(T("Add").Text, "ChooseWidget", new { layerId = Model.CurrentLayer.Id, zone, returnUrl }, new { @class = "button" })</div> <ul class="widgets-zone-widgets"> - @{ + @{ int count = widgets.Where(w => w.Zone == zone).Count() - 1; int i = 0; } @@ -45,12 +46,9 @@ @if (i > 0) { <input class="widgets-mover" type="image" name="submit.MoveUp.@widget.Id" src="@Url.Content("~/modules/orchard.widgets/Content/Admin/images/moveup.gif")" alt="Move up" value="@widget.Id" /> } - @if (i < count) { + @if (i++ < count) { <input class="widgets-mover" type="image" name="submit.MoveDown.@widget.Id" src="@Url.Content("~/modules/orchard.widgets/Content/Admin/images/movedown.gif")" alt="Move down" value="@widget.Id" /> } - @{ - i++; - } @Html.ActionLink(HasText(widget.Title) ? widget.Title : widget.TypeDefinition.DisplayName, "EditWidget", new { @widget.Id }) </li> }