Improved core content editing and publishing UI. Fixes #6388.

This commit is contained in:
Daniel Stolt 2017-03-04 09:36:06 +01:00
parent 162cfd2b67
commit 332a2676dd
11 changed files with 122 additions and 98 deletions

View File

@ -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<IPublishingControlAspect>() && !contentItem.TypeDefinition.Settings.GetModel<ContentTypeSettings>().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<ContentItem> conditionallyPublish) {
private ActionResult CreatePOST(string id, string returnUrl, Func<ContentItem, bool> 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<IPublishingControlAspect>() && !contentItem.TypeDefinition.Settings.GetModel<ContentTypeSettings>().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<ContentItem> conditionallyPublish) {
private ActionResult EditPOST(int id, string returnUrl, Func<ContentItem, bool> 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"));
}

View File

@ -17,10 +17,13 @@ namespace Orchard.Core.Contents.Drivers {
}
protected override DriverResult Editor(ContentPart part, dynamic shapeHelper) {
var results = new List<DriverResult> { ContentShape("Content_SaveButton", saveButton => saveButton) };
var results = new List<DriverResult>();
if (part.TypeDefinition.Settings.GetModel<ContentTypeSettings>().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());
}

View File

@ -6,8 +6,9 @@
Parts_Contents_Publish_SummaryAdmin
-->
<!-- edit "shape" -->
<Place Content_PublishButton="Sidebar:24"/>
<Place Content_SaveButton="Sidebar:23"/>
<Place Content_PublishButton="Sidebar:24"/>
<Place Content_CancelButton="Sidebar:26"/>
<Match DisplayType="Detail">
<Place Parts_Contents_Publish="Content:5"/>
</Match>

View File

@ -0,0 +1,9 @@
@using Orchard.Utility.Extensions
<fieldset class="cancel-button">
@{
var returnUrl = Request.QueryString["returnUrl"];
}
@if (!String.IsNullOrWhiteSpace(returnUrl) && Request.IsLocalUrl(returnUrl)) {
<a id="button-cancel" href="@returnUrl" class="button">@T("Cancel")</a>
}
</fieldset>

View File

@ -1,9 +1,8 @@
@using Orchard.ContentManagement;
@using Orchard.Core.Contents;
@using Orchard.Utility.Extensions;
@if (Authorizer.Authorize(Permissions.PublishContent, (IContent)Model.ContentItem)) {
<fieldset class="publish-button">
<button type="submit" name="submit.Publish" value="submit.Publish">@T("Publish Now")</button>
</fieldset>
<fieldset class="publish-button">
<button class="primaryAction" type="submit" name="submit.Publish" value="submit.Publish">@T("Publish")</button>
</fieldset>
}

View File

@ -1,12 +1,3 @@
@using Orchard.Utility.Extensions
<fieldset class="save-button">
<button class="primaryAction" type="submit" name="submit.Save" value="submit.Save">@T("Save")</button>
@{
var returnUrl = Request.QueryString["returnUrl"];
}
@if (!String.IsNullOrWhiteSpace(returnUrl) && Request.IsLocalUrl(returnUrl)) {
<a id="button-cancel" href="@returnUrl" class="button">@T("Cancel")</a>
}
<fieldset class="save-button">
<button class="primaryAction" type="submit" name="submit.Save" value="submit.Save">@T("Save Draft")</button>
</fieldset>

View File

@ -394,7 +394,9 @@
<ItemGroup>
<Content Include="Common\Views\Parts.Common.Body.Summary.cshtml" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Content Include="Contents\Views\Content.CancelButton.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Contents\Views\Content.cshtml" />
<Content Include="Contents\Views\Content.SummaryAdmin.cshtml" />

View File

@ -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."));
}
}

View File

@ -7,7 +7,7 @@
-->
<!-- edit shape just get default placement -->
<!-- edit "shape" -->
<Place Parts_PublishLater_Edit="Sidebar:25"/><!-- immediately following the contents module's Publish Now button -->
<Place Parts_PublishLater_Edit="Sidebar:25"/>
<!-- default positioning -->
<Match DisplayType="SummaryAdmin">
<Place Parts_PublishLater_Metadata_SummaryAdmin="Meta:1"/>

View File

@ -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)) {
<style type="text/css">
/* TODO: Extract to resource (Decorum). */
using (Script.Head()) {
<style type="text/css">
/* TODO: Extract to resource (Decorum). */
.publish-later-datetime {
float: left;
clear: none;
white-space: nowrap;
vertical-align: middle;
}
.publish-later-datetime {
white-space: nowrap;
vertical-align: middle;
}
.publish-later-datetime legend {
display: none;
}
.publish-later-datetime legend {
display: none;
}
.publish-later-datetime button {
margin-left: 4px;
}
.publish-later-datetime button {
margin-left: 4px;
}
/* RTL */
.dir-rtl .publish-later-datetime {
float: right;
}
/* RTL */
.dir-rtl .publish-later-datetime {
float: right;
}
.dir-rtl .publish-later-datetime button {
margin-left: inherit;
margin-right: 4px;
}
</style>
}
.dir-rtl .publish-later-datetime button {
margin-left: inherit;
margin-right: 4px;
}
</style>
<fieldset class="publish-later-datetime">
<legend>@T("Publish")</legend>
@Html.HiddenFor(m => m.Editor.ShowDate)

View File

@ -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 */