Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish and Save Draft buttons : add "and create new" option #3623

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
80515cb
add "and create new" option on save draft and publish buttons
Skrypt May 12, 2019
c969e55
code cleanup
Skrypt May 12, 2019
be885e2
Add a returnUrl to the contents list for menu content items that are …
Skrypt May 13, 2019
8ca26ef
Move add returnUrl to NavigationManager
Skrypt May 14, 2019
cf34ebf
Implement NavigationItemBuilder ReturnUrl
Skrypt May 14, 2019
bc286e2
simplify code
Skrypt May 15, 2019
eb413d3
menuItem.Url should not be used for returning the proper returnUrl
Skrypt May 15, 2019
53aa91e
simplify code
Skrypt May 15, 2019
85847ac
fix Razor templates
Skrypt May 15, 2019
3771442
code cleanup
Skrypt May 15, 2019
f50d222
moving code block inside "if" to make this more readable
Skrypt May 15, 2019
2d60fda
Use hidden input instead for returnUrl.
Skrypt May 15, 2019
225d2a8
code formatting
Skrypt May 15, 2019
cb75b5b
revert change on AdminMenu (code format)
Skrypt May 15, 2019
1a8af44
Parse refererUrl and return only PathAndQuery part since this should …
Skrypt May 15, 2019
10dfa73
code cleanup
Skrypt May 15, 2019
54b1055
code cleanup
Skrypt May 15, 2019
6c6cedb
Apply same logic with TemplateController
Skrypt May 15, 2019
4604e39
Revert "Use hidden input instead for returnUrl."
Skrypt May 15, 2019
0d522d4
fix button templates
Skrypt May 15, 2019
56e2339
code cleanup
Skrypt May 15, 2019
025e795
code cleanup (removing using)
Skrypt May 15, 2019
4d5a286
Merge remote-tracking branch 'origin/dev' into skrypt/create-and-add
Skrypt May 20, 2019
2737ab1
Merge branch 'dev' into skrypt/create-and-add
Skrypt May 22, 2019
f0f7ee4
Merge branch 'dev' into skrypt/create-and-add
Skrypt May 29, 2019
31024a2
Verify LayerMetadata to return proper url.
Skrypt May 29, 2019
7d720e1
Merge branch 'dev' into skrypt/create-and-add
Skrypt Jun 3, 2019
1317062
Merge branch 'dev' into skrypt/create-and-add
Skrypt Jun 5, 2019
e9cc506
Fix create new button actions in OrchardCore.Menu module
Skrypt Jun 5, 2019
2cfa55b
Merge branch 'dev' into skrypt/create-and-add
Skrypt Jan 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.Contents/AdminMenu.cs
@@ -1,6 +1,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Localization;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Metadata;
Expand Down Expand Up @@ -55,6 +58,10 @@ public async Task BuildNavigationAsync(string name, NavigationBuilder builder)
var ci = await _contentManager.NewAsync(contentTypeDefinition.Name);
var cim = await _contentManager.PopulateAspectAsync<ContentItemMetadata>(ci);
var createRouteValues = cim.CreateRouteValues;

//We add a returnUrl to the contents list for these menu items
createRouteValues.Add("returnUrl", "/Admin/Contents/ContentItems");

Skrypt marked this conversation as resolved.
Show resolved Hide resolved
if (createRouteValues.Any())
newMenu.Add(new LocalizedString(contentTypeDefinition.DisplayName, contentTypeDefinition.DisplayName), "5", item => item
.Action(cim.CreateRouteValues["Action"] as string, cim.CreateRouteValues["Controller"] as string, cim.CreateRouteValues)
Expand Down
Expand Up @@ -78,11 +78,11 @@ public async Task<IActionResult> List(ListContentsViewModel model, PagerParamete

var query = _session.Query<ContentItem, ContentItemIndex>();

if (!string.IsNullOrEmpty(model.DisplayText))
if (!String.IsNullOrEmpty(model.DisplayText))
{
query = query.With<ContentItemIndex>(x => x.DisplayText.Contains(model.DisplayText));
}

switch (model.Options.ContentsStatus)
{
case ContentsStatus.Published:
Expand All @@ -104,7 +104,7 @@ public async Task<IActionResult> List(ListContentsViewModel model, PagerParamete
model.Id = typeId;
}

if (!string.IsNullOrEmpty(model.TypeName))
if (!String.IsNullOrEmpty(model.TypeName))
{
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(model.TypeName);
if (contentTypeDefinition == null)
Expand Down Expand Up @@ -170,7 +170,7 @@ public async Task<IActionResult> List(ListContentsViewModel model, PagerParamete

var routeData = new RouteData();
routeData.Values.Add("DisplayText", model.DisplayText);

var pagerShape = (await New.Pager(pager)).TotalItemCount(maxPagedCount > 0 ? maxPagedCount : await query.CountAsync()).RouteData(routeData);
var pageOfContentItems = await query.Skip(pager.GetStartIndex()).Take(pager.PageSize).ListAsync();

Expand Down Expand Up @@ -234,7 +234,7 @@ private async Task<IEnumerable<ContentTypeDefinition>> GetListableTypesAsync()
// routeValues["Options.SelectedCulture"] = options.SelectedCulture; //todo: don't hard-code the key
// routeValues["Options.OrderBy"] = options.OrderBy; //todo: don't hard-code the key
// routeValues["Options.ContentsStatus"] = options.ContentsStatus; //todo: don't hard-code the key
// if (GetListableTypes(false).Any(ctd => string.Equals(ctd.Name, options.SelectedFilter, StringComparison.OrdinalIgnoreCase)))
// if (GetListableTypes(false).Any(ctd => String.Equals(ctd.Name, options.SelectedFilter, StringComparison.OrdinalIgnoreCase)))
// {
// routeValues["id"] = options.SelectedFilter;
// }
Expand Down Expand Up @@ -338,11 +338,13 @@ public async Task<IActionResult> Create(string id)
public Task<IActionResult> CreatePOST(string id, [Bind(Prefix = "submit.Save")] string submitSave, string returnUrl)
{
var stayOnSamePage = submitSave == "submit.SaveAndContinue";
return CreatePOST(id, returnUrl, stayOnSamePage, contentItem =>
var createNewAfterCreate = submitSave == "submit.SaveAndCreateNew";

return CreatePOST(id, returnUrl, stayOnSamePage, createNewAfterCreate, contentItem =>
{
var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

_notifier.Success(string.IsNullOrWhiteSpace(typeDefinition.DisplayName)
_notifier.Success(String.IsNullOrWhiteSpace(typeDefinition.DisplayName)
? T["Your content draft has been saved."]
: T["Your {0} draft has been saved.", typeDefinition.DisplayName]);

Expand All @@ -355,6 +357,8 @@ public Task<IActionResult> CreatePOST(string id, [Bind(Prefix = "submit.Save")]
public async Task<IActionResult> CreateAndPublishPOST(string id, [Bind(Prefix = "submit.Publish")] string submitPublish, string returnUrl)
{
var stayOnSamePage = submitPublish == "submit.PublishAndContinue";
var createNewAfterCreate = submitPublish == "submit.PublishAndCreateNew";

// pass a dummy content to the authorization check to check for "own" variations
var dummyContent = await _contentManager.NewAsync(id);

Expand All @@ -364,19 +368,19 @@ public async Task<IActionResult> CreateAndPublishPOST(string id, [Bind(Prefix =
return Unauthorized();
}

return await CreatePOST(id, returnUrl, stayOnSamePage, async contentItem =>
return await CreatePOST(id, returnUrl, stayOnSamePage, createNewAfterCreate, async contentItem =>
{
await _contentManager.PublishAsync(contentItem);

var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

_notifier.Success(string.IsNullOrWhiteSpace(typeDefinition.DisplayName)
_notifier.Success(String.IsNullOrWhiteSpace(typeDefinition.DisplayName)
? T["Your content has been published."]
: T["Your {0} has been published.", typeDefinition.DisplayName]);
});
}

private async Task<IActionResult> CreatePOST(string id, string returnUrl, bool stayOnSamePage, Func<ContentItem, Task> conditionallyPublish)
private async Task<IActionResult> CreatePOST(string id, string returnUrl, bool stayOnSamePage, bool createNewAfterCreate, Func<ContentItem, Task> conditionallyPublish)
{
var contentItem = await _contentManager.NewAsync(id);

Expand All @@ -400,14 +404,22 @@ private async Task<IActionResult> CreatePOST(string id, string returnUrl, bool s

await conditionallyPublish(contentItem);

if ((!string.IsNullOrEmpty(returnUrl)) && (!stayOnSamePage))
if (createNewAfterCreate)
{
return LocalRedirect(returnUrl);
return RedirectToAction("Create", new RouteValueDictionary { { "id", id }, { "returnUrl", returnUrl } });

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest this would require a second thought. This makes the Contents module dependent on the Layers module which is not so good.

}
else
{
if (!String.IsNullOrEmpty(returnUrl) && !stayOnSamePage)
{
return LocalRedirect(returnUrl);
}
}

var adminRouteValues = (await _contentManager.PopulateAspectAsync<ContentItemMetadata>(contentItem)).AdminRouteValues;

if (!string.IsNullOrEmpty(returnUrl))
if (!String.IsNullOrEmpty(returnUrl))
{
adminRouteValues.Add("returnUrl", returnUrl);
}
Expand Down Expand Up @@ -456,11 +468,13 @@ public async Task<IActionResult> Edit(string contentItemId)
public Task<IActionResult> EditPOST(string contentItemId, [Bind(Prefix = "submit.Save")] string submitSave, string returnUrl)
{
var stayOnSamePage = submitSave == "submit.SaveAndContinue";
return EditPOST(contentItemId, returnUrl, stayOnSamePage, contentItem =>
var createNewAfterEdit = submitSave == "submit.SaveAndCreateNew";

return EditPOST(contentItemId, returnUrl, stayOnSamePage, createNewAfterEdit, contentItem =>
{
var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

_notifier.Success(string.IsNullOrWhiteSpace(typeDefinition.DisplayName)
_notifier.Success(String.IsNullOrWhiteSpace(typeDefinition.DisplayName)
? T["Your content draft has been saved."]
: T["Your {0} draft has been saved.", typeDefinition.DisplayName]);

Expand All @@ -470,9 +484,10 @@ public Task<IActionResult> EditPOST(string contentItemId, [Bind(Prefix = "submit

[HttpPost, ActionName("Edit")]
[FormValueRequired("submit.Publish")]
public async Task<IActionResult> EditAndPublishPOST(string contentItemId, [Bind(Prefix ="submit.Publish")] string submitPublish, string returnUrl)
public async Task<IActionResult> EditAndPublishPOST(string contentItemId, [Bind(Prefix = "submit.Publish")] string submitPublish, string returnUrl)
{
var stayOnSamePage = submitPublish == "submit.PublishAndContinue";
var createNewAfterEdit = submitPublish == "submit.PublishAndCreateNew";

var content = await _contentManager.GetAsync(contentItemId, VersionOptions.Latest);

Expand All @@ -485,19 +500,19 @@ public async Task<IActionResult> EditAndPublishPOST(string contentItemId, [Bind(
{
return Unauthorized();
}
return await EditPOST(contentItemId, returnUrl, stayOnSamePage, async contentItem =>
return await EditPOST(contentItemId, returnUrl, stayOnSamePage, createNewAfterEdit, async contentItem =>
{
await _contentManager.PublishAsync(contentItem);

var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

_notifier.Success(string.IsNullOrWhiteSpace(typeDefinition.DisplayName)
_notifier.Success(String.IsNullOrWhiteSpace(typeDefinition.DisplayName)
? T["Your content has been published."]
: T["Your {0} has been published.", typeDefinition.DisplayName]);
});
}

private async Task<IActionResult> EditPOST(string contentItemId, string returnUrl, bool stayOnSamePage, Func<ContentItem, Task> conditionallyPublish)
private async Task<IActionResult> EditPOST(string contentItemId, string returnUrl, bool stayOnSamePage, bool createNewAfterEdit, Func<ContentItem, Task> conditionallyPublish)
{
var contentItem = await _contentManager.GetAsync(contentItemId, VersionOptions.DraftRequired);

Expand All @@ -513,7 +528,7 @@ private async Task<IActionResult> EditPOST(string contentItemId, string returnUr

//string previousRoute = null;
//if (contentItem.Has<IAliasAspect>() &&
// !string.IsNullOrWhiteSpace(returnUrl)
// !String.IsNullOrWhiteSpace(returnUrl)
// && Request.IsLocalUrl(returnUrl)
// // only if the original returnUrl is the content itself
// && String.Equals(returnUrl, Url.ItemDisplayUrl(contentItem), StringComparison.OrdinalIgnoreCase)
Expand All @@ -533,7 +548,7 @@ private async Task<IActionResult> EditPOST(string contentItemId, string returnUr
// executed some query which would flush the saved entities inside the above UpdateEditorAsync.
_session.Save(contentItem);

await conditionallyPublish(contentItem);
await conditionallyPublish(contentItem);

if (returnUrl == null)
{
Expand All @@ -543,6 +558,10 @@ private async Task<IActionResult> EditPOST(string contentItemId, string returnUr
{
return RedirectToAction("Edit", new RouteValueDictionary { { "ContentItemId", contentItem.ContentItemId }, { "returnUrl", returnUrl } });
}
else if (createNewAfterEdit)
{
return RedirectToAction("Create", new RouteValueDictionary { { "id", contentItem.ContentType }, { "returnUrl", returnUrl } });
}
else
{
return LocalRedirect(returnUrl);
Expand Down Expand Up @@ -599,7 +618,7 @@ public async Task<IActionResult> DiscardDraft(string contentItemId, string retur

await _contentManager.DiscardDraftAsync(contentItem);

_notifier.Success(string.IsNullOrWhiteSpace(typeDefinition.DisplayName)
_notifier.Success(String.IsNullOrWhiteSpace(typeDefinition.DisplayName)
? T["The draft has been removed."]
: T["The {0} draft has been removed.", typeDefinition.DisplayName]);
}
Expand All @@ -623,7 +642,7 @@ public async Task<IActionResult> Remove(string contentItemId, string returnUrl)

await _contentManager.RemoveAsync(contentItem);

_notifier.Success(string.IsNullOrWhiteSpace(typeDefinition.DisplayName)
_notifier.Success(String.IsNullOrWhiteSpace(typeDefinition.DisplayName)
? T["That content has been removed."]
: T["That {0} has been removed.", typeDefinition.DisplayName]);
}
Expand All @@ -649,7 +668,7 @@ public async Task<IActionResult> Publish(string contentItemId, string returnUrl)

var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

if (string.IsNullOrEmpty(typeDefinition.DisplayName))
if (String.IsNullOrEmpty(typeDefinition.DisplayName))
{
_notifier.Success(T["That content has been published."]);
}
Expand Down Expand Up @@ -679,7 +698,7 @@ public async Task<IActionResult> Unpublish(string contentItemId, string returnUr

var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);

if (string.IsNullOrEmpty(typeDefinition.DisplayName))
if (String.IsNullOrEmpty(typeDefinition.DisplayName))
{
_notifier.Success(T["The content has been unpublished."]);
}
Expand Down
Expand Up @@ -15,6 +15,7 @@ else
</button>
<div class="dropdown-menu">
<button class="dropdown-item" type="submit" name="submit.Publish" value="submit.PublishAndContinue">@T["and continue"]</button>
<button class="dropdown-item" type="submit" name="submit.Publish" value="submit.PublishAndCreateNew">@T["and create new"]</button>
</div>
</div>
}
Expand Down
Expand Up @@ -14,6 +14,7 @@ else
</button>
<div class="dropdown-menu">
<button class="dropdown-item" type="submit" name="submit.Save" value="submit.SaveAndContinue">@T["and continue"]</button>
<button class="dropdown-item" type="submit" name="submit.Save" value="submit.SaveAndCreateNew">@T["and create new"]</button>
</div>
</div>
}
@@ -1,5 +1,5 @@
@model TemplateViewModel
@{
@{
var returnUrl = ViewData["returnUrl"]?.ToString();
}

Expand All @@ -20,7 +20,7 @@
<div class="form-group" asp-validation-class-for="Name">
<label asp-for="Name">@T["Name"]</label>
<span asp-validation-for="Name" class="text-danger">@T["The name is required."]</span>
<input asp-for="Name" class="form-control" autofocus/>
<input asp-for="Name" class="form-control" autofocus />
<span class="hint">@T["The name of the template."]</span>
</div>

Expand All @@ -45,11 +45,12 @@
</button>
<div class="dropdown-menu">
<button class="dropdown-item" name="submit" type="submit" value="SaveAndContinue">@T["and continue"]</button>
<button class="dropdown-item" name="submit" type="submit" value="SaveAndCreateNew">@T["and create new"]</button>
</div>
</div>

@if (Url.IsLocalUrl(returnUrl))
{
{
<a class="btn btn-secondary" href="@returnUrl">@T["Cancel"]</a>
}
<a class="btn btn-info" href="@Url.Action("Index", "Preview", new { area = "OrchardCore.Templates" })" target="_blank">@T["Preview"]</a>
Expand Down
Expand Up @@ -48,13 +48,14 @@
</button>
<div class="dropdown-menu">
<button class="dropdown-item" name="submit" type="submit" value="SaveAndContinue">@T["and continue"]</button>
<button class="dropdown-item" name="submit" type="submit" value="SaveAndCreateNew">@T["and create new"]</button>
</div>
</div>

@if (Url.IsLocalUrl(returnUrl))
{
<a class="btn btn-secondary" href="@returnUrl">@T["Cancel"]</a>
}
}
<a class="btn btn-info" href="@Url.Action("Index", "Preview", new { area = "OrchardCore.Templates" })" target="_blank">@T["Preview"]</a>
</div>
</fieldset>
Expand Down