From 332a2676dddf0a08458d287f48d0feaa1bd82eea Mon Sep 17 00:00:00 2001 From: Daniel Stolt Date: Sat, 4 Mar 2017 09:36:06 +0100 Subject: [PATCH] Improved core content editing and publishing UI. Fixes #6388. --- .../Contents/Controllers/AdminController.cs | 94 ++++++++++++------- .../Core/Contents/Drivers/ContentsDriver.cs | 7 +- src/Orchard.Web/Core/Contents/Placement.info | 3 +- .../Views/Content.CancelButton.cshtml | 9 ++ .../Views/Content.PublishButton.cshtml | 7 +- .../Contents/Views/Content.SaveButton.cshtml | 13 +-- src/Orchard.Web/Core/Orchard.Core.csproj | 4 +- .../Drivers/PublishLaterPartDriver.cs | 2 +- .../Orchard.PublishLater/Placement.info | 2 +- .../EditorTemplates/Parts/PublishLater.cshtml | 50 +++++----- .../Themes/TheAdmin/Styles/site.css | 29 +++--- 11 files changed, 122 insertions(+), 98 deletions(-) create mode 100644 src/Orchard.Web/Core/Contents/Views/Content.CancelButton.cshtml diff --git a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs index c66b7bf04..58aff7de2 100644 --- a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs +++ b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs @@ -265,10 +265,7 @@ namespace Orchard.Core.Contents.Controllers { [HttpPost, ActionName("Create")] [Mvc.FormValueRequired("submit.Save")] public ActionResult CreatePOST(string id, string returnUrl) { - return CreatePOST(id, returnUrl, contentItem => { - if (!contentItem.Has() && !contentItem.TypeDefinition.Settings.GetModel().Draftable) - _contentManager.Publish(contentItem); - }); + return CreatePOST(id, returnUrl, contentItem => { return false; }); } [HttpPost, ActionName("Create")] @@ -278,16 +275,19 @@ namespace Orchard.Core.Contents.Controllers { // pass a dummy content to the authorization check to check for "own" variations var dummyContent = _contentManager.New(id); - if (!Services.Authorizer.Authorize(Permissions.PublishContent, dummyContent, T("Couldn't create content"))) + if (!Services.Authorizer.Authorize(Permissions.PublishContent, dummyContent, T("You do not have permission to publish content."))) return new HttpUnauthorizedResult(); - return CreatePOST(id, returnUrl, contentItem => _contentManager.Publish(contentItem)); + return CreatePOST(id, returnUrl, contentItem => { + _contentManager.Publish(contentItem); + return true; + }); } - private ActionResult CreatePOST(string id, string returnUrl, Action conditionallyPublish) { + private ActionResult CreatePOST(string id, string returnUrl, Func conditionallyPublish) { var contentItem = _contentManager.New(id); - if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Couldn't create content"))) + if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("You do not have permission to edit content."))) return new HttpUnauthorizedResult(); _contentManager.Create(contentItem, VersionOptions.Draft); @@ -299,14 +299,23 @@ namespace Orchard.Core.Contents.Controllers { return View(model); } - conditionallyPublish(contentItem); + var contentWasPublished = conditionallyPublish(contentItem); + + if (contentWasPublished) { + Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) + ? T("The content has been created and published.") + : T("The {0} has been created and published.", contentItem.TypeDefinition.DisplayName)); + } + else { + Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) + ? T("The content has been created as a draft.") + : T("The {0} has been created as a draft.", contentItem.TypeDefinition.DisplayName)); + } - Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) - ? T("Your content has been created.") - : T("Your {0} has been created.", contentItem.TypeDefinition.DisplayName)); if (!string.IsNullOrEmpty(returnUrl)) { return this.RedirectLocal(returnUrl); } + var adminRouteValues = _contentManager.GetItemMetadata(contentItem).AdminRouteValues; return RedirectToRoute(adminRouteValues); } @@ -317,7 +326,7 @@ namespace Orchard.Core.Contents.Controllers { if (contentItem == null) return HttpNotFound(); - if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Cannot edit content"))) + if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("You do not have permission to edit content."))) return new HttpUnauthorizedResult(); var model = _contentManager.BuildEditor(contentItem); @@ -327,10 +336,7 @@ namespace Orchard.Core.Contents.Controllers { [HttpPost, ActionName("Edit")] [Mvc.FormValueRequired("submit.Save")] public ActionResult EditPOST(int id, string returnUrl) { - return EditPOST(id, returnUrl, contentItem => { - if (!contentItem.Has() && !contentItem.TypeDefinition.Settings.GetModel().Draftable) - _contentManager.Publish(contentItem); - }); + return EditPOST(id, returnUrl, contentItem => { return false; }); } [HttpPost, ActionName("Edit")] @@ -341,19 +347,22 @@ namespace Orchard.Core.Contents.Controllers { if (content == null) return HttpNotFound(); - if (!Services.Authorizer.Authorize(Permissions.PublishContent, content, T("Couldn't publish content"))) + if (!Services.Authorizer.Authorize(Permissions.PublishContent, content, T("You do not have permission to publish content."))) return new HttpUnauthorizedResult(); - return EditPOST(id, returnUrl, contentItem => _contentManager.Publish(contentItem)); + return EditPOST(id, returnUrl, contentItem => { + _contentManager.Publish(contentItem); + return true; + }); } - private ActionResult EditPOST(int id, string returnUrl, Action conditionallyPublish) { + private ActionResult EditPOST(int id, string returnUrl, Func conditionallyPublish) { var contentItem = _contentManager.Get(id, VersionOptions.DraftRequired); if (contentItem == null) return HttpNotFound(); - if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Couldn't edit content"))) + if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("You do not have permission to edit content."))) return new HttpUnauthorizedResult(); string previousRoute = null; @@ -372,7 +381,7 @@ namespace Orchard.Core.Contents.Controllers { return View("Edit", model); } - conditionallyPublish(contentItem); + var contentWasPublished = conditionallyPublish(contentItem); if (!string.IsNullOrWhiteSpace(returnUrl) && previousRoute != null @@ -380,9 +389,16 @@ namespace Orchard.Core.Contents.Controllers { returnUrl = Url.ItemDisplayUrl(contentItem); } - Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) - ? T("Your content has been saved.") - : T("Your {0} has been saved.", contentItem.TypeDefinition.DisplayName)); + if (contentWasPublished) { + Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) + ? T("The content has been published.") + : T("The {0} has been published.", contentItem.TypeDefinition.DisplayName)); + } + else { + Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) + ? T("The content has been saved as a draft.") + : T("The {0} has been saved as a draft.", contentItem.TypeDefinition.DisplayName)); + } return this.RedirectLocal(returnUrl, () => RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } })); } @@ -391,18 +407,20 @@ namespace Orchard.Core.Contents.Controllers { public ActionResult Clone(int id) { var originalContentItem = _contentManager.GetLatest(id); - if (!Services.Authorizer.Authorize(Permissions.ViewContent, originalContentItem, T("Couldn't open original content"))) + if (!Services.Authorizer.Authorize(Permissions.ViewContent, originalContentItem, T("You do not have permission to view existing content."))) return new HttpUnauthorizedResult(); // pass a dummy content to the authorization check to check for "own" variations var dummyContent = _contentManager.New(originalContentItem.ContentType); - if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("Couldn't create clone content"))) + if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("You do not have permission to edit (or create) content."))) return new HttpUnauthorizedResult(); var cloneContentItem = _contentManager.Clone(originalContentItem); - Services.Notifier.Success(T("Successfully cloned. The clone was saved as a draft.")); + Services.Notifier.Success(string.IsNullOrWhiteSpace(originalContentItem.TypeDefinition.DisplayName) + ? T("The content has been cloned as a draft.") + : T("The {0} has been cloned as a draft.", originalContentItem.TypeDefinition.DisplayName)); var adminRouteValues = _contentManager.GetItemMetadata(cloneContentItem).AdminRouteValues; return RedirectToRoute(adminRouteValues); @@ -412,7 +430,7 @@ namespace Orchard.Core.Contents.Controllers { public ActionResult Remove(int id, string returnUrl) { var contentItem = _contentManager.Get(id, VersionOptions.Latest); - if (!Services.Authorizer.Authorize(Permissions.DeleteContent, contentItem, T("Couldn't remove content"))) + if (!Services.Authorizer.Authorize(Permissions.DeleteContent, contentItem, T("You do not have permission to delete content."))) return new HttpUnauthorizedResult(); if (contentItem != null) { @@ -439,15 +457,15 @@ namespace Orchard.Core.Contents.Controllers { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } - if (!Services.Authorizer.Authorize(Permissions.DeleteContent, contentItem, T("Couldn't remove draft"))) { + if (!Services.Authorizer.Authorize(Permissions.DeleteContent, contentItem, T("You do not have permission to delete content (or discard draft content)."))) { return new HttpUnauthorizedResult(); } _contentManager.DiscardDraft(contentItem); Services.Notifier.Information(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) - ? T("That draft has been removed.") - : T("That {0} draft has been removed.", contentItem.TypeDefinition.DisplayName)); + ? T("The draft content has been removed.") + : T("The draft {0} has been removed.", contentItem.TypeDefinition.DisplayName)); return this.RedirectLocal(returnUrl, () => RedirectToAction("List")); } @@ -458,12 +476,14 @@ namespace Orchard.Core.Contents.Controllers { if (contentItem == null) return HttpNotFound(); - if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("Couldn't publish content"))) + if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("You do not have permission to publish content."))) return new HttpUnauthorizedResult(); _contentManager.Publish(contentItem); - Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) ? T("The content has been published.") : T("The {0} has been published.", contentItem.TypeDefinition.DisplayName)); + Services.Notifier.Information(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) + ? T("The content has been published.") + : T("The {0} has been published.", contentItem.TypeDefinition.DisplayName)); return this.RedirectLocal(returnUrl, () => RedirectToAction("List")); } @@ -474,12 +494,14 @@ namespace Orchard.Core.Contents.Controllers { if (contentItem == null) return HttpNotFound(); - if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("Couldn't unpublish content"))) + if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("You do not have permission to publish (or unpublish) content."))) return new HttpUnauthorizedResult(); _contentManager.Unpublish(contentItem); - Services.Notifier.Success(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) ? T("The content has been unpublished.") : T("The {0} has been unpublished.", contentItem.TypeDefinition.DisplayName)); + Services.Notifier.Information(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName) + ? T("The content has been unpublished.") + : T("The {0} has been unpublished.", contentItem.TypeDefinition.DisplayName)); return this.RedirectLocal(returnUrl, () => RedirectToAction("List")); } diff --git a/src/Orchard.Web/Core/Contents/Drivers/ContentsDriver.cs b/src/Orchard.Web/Core/Contents/Drivers/ContentsDriver.cs index bc92e115f..baa2845fd 100644 --- a/src/Orchard.Web/Core/Contents/Drivers/ContentsDriver.cs +++ b/src/Orchard.Web/Core/Contents/Drivers/ContentsDriver.cs @@ -17,10 +17,13 @@ namespace Orchard.Core.Contents.Drivers { } protected override DriverResult Editor(ContentPart part, dynamic shapeHelper) { - var results = new List { ContentShape("Content_SaveButton", saveButton => saveButton) }; + var results = new List(); if (part.TypeDefinition.Settings.GetModel().Draftable) - results.Add(ContentShape("Content_PublishButton", publishButton => publishButton)); + results.Add(ContentShape("Content_SaveButton", saveButton => saveButton)); + + results.Add(ContentShape("Content_PublishButton", publishButton => publishButton)); + results.Add(ContentShape("Content_CancelButton", cancelButton => cancelButton)); return Combined(results.ToArray()); } diff --git a/src/Orchard.Web/Core/Contents/Placement.info b/src/Orchard.Web/Core/Contents/Placement.info index 1380b93f0..30362f02a 100644 --- a/src/Orchard.Web/Core/Contents/Placement.info +++ b/src/Orchard.Web/Core/Contents/Placement.info @@ -6,8 +6,9 @@ Parts_Contents_Publish_SummaryAdmin --> - + + diff --git a/src/Orchard.Web/Core/Contents/Views/Content.CancelButton.cshtml b/src/Orchard.Web/Core/Contents/Views/Content.CancelButton.cshtml new file mode 100644 index 000000000..b60dc90f9 --- /dev/null +++ b/src/Orchard.Web/Core/Contents/Views/Content.CancelButton.cshtml @@ -0,0 +1,9 @@ +@using Orchard.Utility.Extensions +
+ @{ + var returnUrl = Request.QueryString["returnUrl"]; + } + @if (!String.IsNullOrWhiteSpace(returnUrl) && Request.IsLocalUrl(returnUrl)) { + @T("Cancel") + } +
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Contents/Views/Content.PublishButton.cshtml b/src/Orchard.Web/Core/Contents/Views/Content.PublishButton.cshtml index 7590a0c0d..d376b2911 100644 --- a/src/Orchard.Web/Core/Contents/Views/Content.PublishButton.cshtml +++ b/src/Orchard.Web/Core/Contents/Views/Content.PublishButton.cshtml @@ -1,9 +1,8 @@ @using Orchard.ContentManagement; @using Orchard.Core.Contents; -@using Orchard.Utility.Extensions; @if (Authorizer.Authorize(Permissions.PublishContent, (IContent)Model.ContentItem)) { -
- -
+
+ +
} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Contents/Views/Content.SaveButton.cshtml b/src/Orchard.Web/Core/Contents/Views/Content.SaveButton.cshtml index a9275bcad..86b5a1b55 100644 --- a/src/Orchard.Web/Core/Contents/Views/Content.SaveButton.cshtml +++ b/src/Orchard.Web/Core/Contents/Views/Content.SaveButton.cshtml @@ -1,12 +1,3 @@ -@using Orchard.Utility.Extensions -
- - - @{ - var returnUrl = Request.QueryString["returnUrl"]; - } - - @if (!String.IsNullOrWhiteSpace(returnUrl) && Request.IsLocalUrl(returnUrl)) { - @T("Cancel") - } +
+
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index 5ae0fc352..69102609f 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -394,7 +394,9 @@ - + + + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs b/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs index bef714637..12bcc1032 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs @@ -105,7 +105,7 @@ namespace Orchard.PublishLater.Drivers { } } else { - updater.AddModelError(Prefix, T("Both the date and time need to be specified for when this is to be published. If you don't want to schedule publishing then click Save or Publish Now.")); + updater.AddModelError(Prefix, T("Both the date and time need to be specified for when this is to be published. If you don't want to schedule publishing then click Save Draft or Publish Now.")); } } diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info b/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info index eec14fcbb..957ea6587 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info @@ -7,7 +7,7 @@ --> - + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml index 5dc5b49a1..f879e6ead 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml @@ -1,40 +1,38 @@ @model Orchard.PublishLater.ViewModels.PublishLaterViewModel -@using Orchard.ContentManagement; @using Orchard.Core.Contents; -@using Orchard.Utility.Extensions; @if (Authorizer.Authorize(Permissions.PublishContent, Model.ContentItem)) { - + } - .dir-rtl .publish-later-datetime button { - margin-left: inherit; - margin-right: 4px; - } - -
@T("Publish") @Html.HiddenFor(m => m.Editor.ShowDate) diff --git a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css index 86de76473..af59deac1 100644 --- a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css +++ b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css @@ -1157,25 +1157,24 @@ html.dyn #submit-pager, html.dyn .apply-bulk-actions-auto { display:none; } } /* Core Contents and Orchard.PublishLater */ -.edit-item-sidebar fieldset { - margin:0; - padding:0; +.edit-item-secondary { + margin-top: 2em; } -fieldset.publish-button, fieldset.delete-button, fieldset.save-button { - clear:none; - float:left; +.edit-item-sidebar fieldset { + float: left; + clear: none; + margin: 0; + padding: 0; } -fieldset.save-button { - clear:left; + +.edit-item-sidebar fieldset + fieldset { + margin-left: 12px; } -fieldset.publish-button { - margin: 0 12px 0 0; - padding: 0 12px; - border-right:1px solid #ccc; -} -fieldset.delete-button { - margin: 0 0 0 12px; + +fieldset.cancel-button { + padding-left: 12px; + border-left: 1px solid #ccc; } /* Dashboard */