Initial new List Management UI.

--HG--
branch : dev
This commit is contained in:
Dave Reed
2011-03-10 11:45:07 -08:00
parent 6c068e45ef
commit deb5513737
21 changed files with 573 additions and 75 deletions

View File

@@ -1,12 +1,16 @@
using System.Linq;
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Common.Models;
using Orchard.Core.Containers.Models;
using Orchard.Core.Containers.Settings;
using Orchard.Core.Containers.ViewModels;
using Orchard.Data;
using Orchard.Localization;
using Orchard.UI.Notify;
@@ -42,17 +46,31 @@ namespace Orchard.Core.Containers.Drivers {
Services.Notifier.Warning(T("There are no content types in the system with a Containable part attached. Consider adding a Containable part to some content type, existing or new, in order to relate items to this (Container enabled) item."));
}
return Editor(part, null, shapeHelper);
return Editor(part, (IUpdateModel)null, shapeHelper);
}
protected override DriverResult Editor(ContainerPart part, IUpdateModel updater, dynamic shapeHelper) {
return ContentShape(
"Parts_Container_Edit",
() => {
if (updater != null)
updater.TryUpdateModel(part, "Container", null, null);
var model = new ContainerViewModel { Part = part };
// todo: is there a non-string comparison way to find ConaintableParts?
var containables = _contentDefinitionManager.ListTypeDefinitions().Where(td => td.Parts.Any(p => p.PartDefinition.Name == "ContainablePart")).ToList();
var listItems = new[] { new SelectListItem { Text = T("(Any)").Text, Value = "" } }
.Concat(containables.Select(x => new SelectListItem {
Value = Convert.ToString(x.Name),
Text = x.DisplayName,
Selected = x.Name == model.Part.Record.ItemContentType,
}))
.ToList();
return shapeHelper.EditorTemplate(TemplateName: "Container", Model: part, Prefix: "Container");
model.AvailableContainables = new SelectList(listItems, "Value", "Text", model.Part.Record.ItemContentType);
if (updater != null) {
updater.TryUpdateModel(model, "Container", null, null);
}
return shapeHelper.EditorTemplate(TemplateName: "Container", Model: model, Prefix: "Container");
});
}
}
@@ -71,20 +89,5 @@ namespace Orchard.Core.Containers.Drivers {
part.Record.OrderByDirection = (int)OrderByDirection.Descending;
});
}
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
var container = context.ContentItem.As<ContainerPart>();
if (container == null)
return;
// containers link to their contents in admin screens
context.Metadata.AdminRouteValues = new RouteValueDictionary {
{"Area", "Contents"},
{"Controller", "Admin"},
{"Action", "List"},
{"containerId", container.Id}
};
}
}
}

View File

@@ -45,5 +45,10 @@ namespace Orchard.Core.Containers {
return 1;
}
public int UpdateFrom1() {
SchemaBuilder.AlterTable("ContainerPartRecord", table => table.AddColumn<string>("ItemContentType"));
return 2;
}
}
}

View File

@@ -6,6 +6,7 @@ namespace Orchard.Core.Containers.Models {
}
public class ContainerPartRecord : ContentPartRecord {
public virtual string ItemContentType { get; set; }
public virtual bool Paginated { get; set; }
public virtual int PageSize { get; set; }
public virtual string OrderByProperty { get; set; }

View File

@@ -3,7 +3,6 @@
<!--
Parts_Container_Contained
Parts_Container_Contained_Summary
Parts_Container_Contained_SummaryAdmin
-->
<Place Parts_Containable_Edit="Content:before.3"/>
<Place Parts_Container_Edit="Content:5"/>
@@ -11,7 +10,4 @@
<Place Parts_ContainerWidget_Edit="Content:5"/>
<Place Parts_Container_SiteSettings="Content:10"/>
<Place Parts_ContainerWidget="Content"/>
<Match DisplayType="SummaryAdmin">
<Place Parts_Container_Contained_SummaryAdmin="Actions:10"/>
</Match>
</Placement>

View File

@@ -0,0 +1,9 @@
using System.Web.Mvc;
using Orchard.Core.Containers.Models;
namespace Orchard.Core.Containers.ViewModels {
public class ContainerViewModel {
public ContainerPart Part { get; set; }
public SelectList AvailableContainables { get; set; }
}
}

View File

@@ -1,27 +1,31 @@
@model Orchard.Core.Containers.Models.ContainerPart
@model Orchard.Core.Containers.ViewModels.ContainerViewModel
@using Orchard.Core.Containers.Models;
<fieldset>
@Html.LabelFor(m => m.Record.OrderByProperty, T("Order by"))
<select id="@Html.FieldIdFor(m => m.Record.OrderByProperty)" name="@Html.FieldNameFor(m => m.Record.OrderByProperty)">
@Html.SelectOption(Model.Record.OrderByProperty, "CommonPart.PublishedUtc", T("Date Published").Text)
@Html.SelectOption(Model.Record.OrderByProperty, "RoutePart.Title", T("Title").Text)
@Html.SelectOption(Model.Record.OrderByProperty, "RoutePart.Slug", T("Slug").Text)
@Html.SelectOption(Model.Record.OrderByProperty, "CustomPropertiesPart.CustomOne", T("Custom 1").Text)
@Html.SelectOption(Model.Record.OrderByProperty, "CustomPropertiesPart.CustomTwo", T("Custom 2").Text)
@Html.SelectOption(Model.Record.OrderByProperty, "CustomPropertiesPart.CustomThree", T("Custom 3").Text)
@Html.LabelFor(m => m.Part.Record.ItemContentType, T("Contains"))
@Html.DropDownListFor(m => m.Part.Record.ItemContentType, Model.AvailableContainables)
</fieldset>
<fieldset>
@Html.LabelFor(m => m.Part.Record.OrderByProperty, T("Order by"))
<select id="@Html.FieldIdFor(m => m.Part.Record.OrderByProperty)" name="@Html.FieldNameFor(m => m.Part.Record.OrderByProperty)">
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CommonPart.PublishedUtc", T("Date Published").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "RoutePart.Title", T("Title").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "RoutePart.Slug", T("Slug").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CustomPropertiesPart.CustomOne", T("Custom 1").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CustomPropertiesPart.CustomTwo", T("Custom 2").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CustomPropertiesPart.CustomThree", T("Custom 3").Text)
</select>
<select id="@Html.FieldIdFor(m => m.Record.OrderByDirection)" name="@Html.FieldNameFor(m => m.Record.OrderByDirection)">
@Html.SelectOption(Model.Record.OrderByDirection, (int)OrderByDirection.Ascending, T("Ascending").Text)
@Html.SelectOption(Model.Record.OrderByDirection, (int)OrderByDirection.Descending, T("Descending").Text)
<select id="@Html.FieldIdFor(m => m.Part.Record.OrderByDirection)" name="@Html.FieldNameFor(m => m.Part.Record.OrderByDirection)">
@Html.SelectOption(Model.Part.Record.OrderByDirection, (int)OrderByDirection.Ascending, T("Ascending").Text)
@Html.SelectOption(Model.Part.Record.OrderByDirection, (int)OrderByDirection.Descending, T("Descending").Text)
</select>
</fieldset>
<fieldset class="with-checkbox">
<span>
@Html.LabelFor(m => m.Record.PageSize, T("Page size"))
@Html.TextBoxFor(m => m.Record.PageSize, new { @class = "text text-small" })
@Html.LabelFor(m => m.Part.Record.PageSize, T("Page size"))
@Html.TextBoxFor(m => m.Part.Record.PageSize, new { @class = "text text-small" })
</span>
<span class="checkbox-and-label">
@Html.CheckBoxFor(m => m.Record.Paginated)
<label for="@Html.FieldIdFor(m => m.Record.Paginated)" class="forcheckbox">@T("Show paging controls")</label>
@Html.CheckBoxFor(m => m.Part.Record.Paginated)
<label for="@Html.FieldIdFor(m => m.Part.Record.Paginated)" class="forcheckbox">@T("Show paging controls")</label>
</span>
</fieldset>

View File

@@ -9,6 +9,7 @@ using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Core.Common.Models;
using Orchard.Core.Containers.Models;
using Orchard.Core.Contents.Settings;
using Orchard.Core.Contents.ViewModels;
using Orchard.Data;
@@ -52,10 +53,8 @@ namespace Orchard.Core.Contents.Controllers {
public ActionResult List(ListContentsViewModel model, PagerParameters pagerParameters) {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
if (model.ContainerId != null && _contentManager.GetLatest((int)model.ContainerId) == null)
return HttpNotFound();
var query = _contentManager.Query(VersionOptions.Latest, GetCreatableTypes().Select(ctd => ctd.Name).ToArray());
var query = _contentManager.Query(VersionOptions.Latest, GetCreatableTypes(false).Select(ctd => ctd.Name).ToArray());
if (!string.IsNullOrEmpty(model.TypeName)) {
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(model.TypeName);
@@ -68,10 +67,6 @@ namespace Orchard.Core.Contents.Controllers {
query = query.ForType(model.TypeName);
}
if (model.ContainerId != null) {
query = query.Join<CommonPartRecord>().Where(cr => cr.Container.Id == model.ContainerId);
}
switch (model.Options.OrderBy) {
case ContentsOrder.Modified:
//query = query.OrderByDescending<ContentPartRecord, int>(ci => ci.ContentItemRecord.Versions.Single(civr => civr.Latest).Id);
@@ -87,7 +82,7 @@ namespace Orchard.Core.Contents.Controllers {
}
model.Options.SelectedFilter = model.TypeName;
model.Options.FilterOptions = GetCreatableTypes()
model.Options.FilterOptions = GetCreatableTypes(false)
.Select(ctd => new KeyValuePair<string, string>(ctd.Name, ctd.DisplayName))
.ToList().OrderBy(kvp => kvp.Key);
@@ -107,8 +102,8 @@ namespace Orchard.Core.Contents.Controllers {
return View((object)viewModel);
}
private IEnumerable<ContentTypeDefinition> GetCreatableTypes() {
return _contentDefinitionManager.ListTypeDefinitions().Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Creatable);
private IEnumerable<ContentTypeDefinition> GetCreatableTypes(bool andContainable) {
return _contentDefinitionManager.ListTypeDefinitions().Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Creatable && (!andContainable || ctd.Parts.Any(p => p.PartDefinition.Name == "ContainablePart")) );
}
[HttpPost, ActionName("List")]
@@ -117,7 +112,7 @@ namespace Orchard.Core.Contents.Controllers {
var routeValues = ControllerContext.RouteData.Values;
if (options != null) {
routeValues["Options.OrderBy"] = options.OrderBy; //todo: don't hard-code the key
if (GetCreatableTypes().Any(ctd => string.Equals(ctd.Name, options.SelectedFilter, StringComparison.OrdinalIgnoreCase))) {
if (GetCreatableTypes(false).Any(ctd => string.Equals(ctd.Name, options.SelectedFilter, StringComparison.OrdinalIgnoreCase))) {
routeValues["id"] = options.SelectedFilter;
}
else {
@@ -177,22 +172,29 @@ namespace Orchard.Core.Contents.Controllers {
return this.RedirectLocal(returnUrl, () => RedirectToAction("List"));
}
ActionResult CreatableTypeList() {
dynamic viewModel = Shape.ViewModel(ContentTypes: GetCreatableTypes());
ActionResult CreatableTypeList(int? containerId) {
dynamic viewModel = Shape.ViewModel(ContentTypes: GetCreatableTypes(containerId.HasValue), ContainerId: containerId);
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View("CreatableTypeList", (object)viewModel);
}
public ActionResult Create(string id) {
public ActionResult Create(string id, int? containerId) {
if (string.IsNullOrEmpty(id))
return CreatableTypeList();
return CreatableTypeList(containerId);
var contentItem = _contentManager.New(id);
if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("Cannot create content")))
return new HttpUnauthorizedResult();
if (containerId.HasValue && contentItem.Is<ContainablePart>()) {
var common = contentItem.As<CommonPart>();
if (common != null) {
common.Container = _contentManager.Get(containerId.Value);
}
}
dynamic model = _contentManager.BuildEditor(contentItem);
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)model);

View File

@@ -8,7 +8,6 @@ namespace Orchard.Core.Contents.ViewModels {
}
public string Id { get; set; }
public int? ContainerId { get; set; }
public string TypeName {
get { return Id; }

View File

@@ -1,5 +1,5 @@
@{ Layout.Title = T("Create New Content").ToString(); }
@foreach (var type in Model.ContentTypes) {
<p>@Html.ActionLink((string)type.DisplayName, "Create", new { Area = "Contents", Id = (string)type.Name })</p>
<p>@Html.ActionLink((string)type.DisplayName, "Create", new { Area = "Contents", Id = (string)type.Name, ContainerId = Model.ContainerId })</p>
}

View File

@@ -87,6 +87,7 @@
<Compile Include="Containers\Settings\ContainerSettings.cs" />
<Compile Include="Containers\ViewModels\ContainableViewModel.cs" />
<Compile Include="Containers\ViewModels\ContainerWidgetViewModel.cs" />
<Compile Include="Containers\ViewModels\ContainerViewModel.cs" />
<Compile Include="Contents\Security\AuthorizationEventHandler.cs" />
<Compile Include="Common\Services\BbcodeFilter.cs" />
<Compile Include="Common\Services\ICommonService.cs" />
@@ -99,7 +100,6 @@
<Compile Include="Contents\Extensions\MetaDataExtensions.cs" />
<Compile Include="Contents\Handlers\ContentsHandler.cs" />
<Compile Include="Contents\Permissions.cs" />
<Compile Include="Contents\Routes.cs" />
<Compile Include="Contents\Settings\ContentTypeSettings.cs" />
<Compile Include="Contents\Settings\ContentPartSettings.cs" />
<Compile Include="Contents\Shapes.cs" />
@@ -383,9 +383,6 @@
<Content Include="Routable\Views\Parts.RoutableTitle_Summary.cshtml" />
<Content Include="Routable\Views\Parts.RoutableTitle_SummaryAdmin.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Containers\Views\Parts.Container.Contained.SummaryAdmin.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Shapes\Views\ShapeResult\Display.cshtml" />
</ItemGroup>

View File

@@ -0,0 +1,269 @@
using System;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Core.Common.Models;
using Orchard.Core.Containers.Models;
using Orchard.Core.Contents;
using Orchard.Core.Contents.Controllers;
using Orchard.Core.Contents.Settings;
using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Shapes;
using Orchard.Lists.ViewModels;
using Orchard.Localization;
using Orchard;
using Orchard.Logging;
using Orchard.Mvc.Extensions;
using Orchard.Settings;
using Orchard.UI.Navigation;
using Orchard.UI.Notify;
namespace Lists.Controllers {
public class AdminController : Controller {
private readonly IContentManager _contentManager;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly ITransactionManager _transactionManager;
private readonly ISiteService _siteService;
public IOrchardServices Services { get; set; }
public AdminController(
IOrchardServices orchardServices,
IContentManager contentManager,
IContentDefinitionManager contentDefinitionManager,
ITransactionManager transactionManager,
ISiteService siteService,
IShapeFactory shapeFactory) {
Services = orchardServices;
_contentManager = contentManager;
_contentDefinitionManager = contentDefinitionManager;
_transactionManager = transactionManager;
_siteService = siteService;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
Shape = shapeFactory;
}
public Localizer T { get; set; }
public ILogger Logger { get; set; }
dynamic Shape { get; set; }
private IEnumerable<ContentTypeDefinition> GetContainableTypes() {
return _contentDefinitionManager.ListTypeDefinitions().Where(ctd => ctd.Parts.Any(c => c.PartDefinition.Name == "ContainablePart") && ctd.Settings.GetModel<ContentTypeSettings>().Creatable);
}
public ActionResult List(ListContentsViewModel model, PagerParameters pagerParameters) {
var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
var container = _contentManager.GetLatest((int)model.ContainerId);
if (container == null) {
return HttpNotFound();
}
var restrictedContentType = container.As<ContainerPart>().Record.ItemContentType;
var hasRestriction = !string.IsNullOrEmpty(restrictedContentType);
var metadata = container.ContentManager.GetItemMetadata(container);
model.ContainerDisplayName = metadata.DisplayText;
if (string.IsNullOrEmpty(model.ContainerDisplayName)) {
model.ContainerDisplayName = container.ContentType;
}
var query = _contentManager.Query(VersionOptions.Latest);
if (hasRestriction) {
model.FilterByContentType = restrictedContentType;
}
if (!string.IsNullOrEmpty(model.FilterByContentType)) {
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(model.FilterByContentType);
if (contentTypeDefinition == null)
return HttpNotFound();
query = query.ForType(model.FilterByContentType);
}
query = query.Join<CommonPartRecord>().Where(cr => cr.Container.Id == model.ContainerId);
switch (model.Options.OrderBy) {
case ContentsOrder.Modified:
query = query.OrderByDescending<CommonPartRecord, DateTime?>(cr => cr.ModifiedUtc);
break;
case ContentsOrder.Published:
query = query.OrderByDescending<CommonPartRecord, DateTime?>(cr => cr.PublishedUtc);
break;
case ContentsOrder.Created:
query = query.OrderByDescending<CommonPartRecord, DateTime?>(cr => cr.CreatedUtc);
break;
}
model.Options.SelectedFilter = model.FilterByContentType;
if (!hasRestriction) {
model.Options.FilterOptions = GetContainableTypes()
.Select(ctd => new KeyValuePair<string, string>(ctd.Name, ctd.DisplayName))
.ToList().OrderBy(kvp => kvp.Key);
}
var pagerShape = Shape.Pager(pager).TotalItemCount(query.Count());
var pageOfContentItems = query.Slice(pager.GetStartIndex(), pager.PageSize).ToList();
var list = Shape.List();
list.AddRange(pageOfContentItems.Select(ci => _contentManager.BuildDisplay(ci, "SummaryAdmin")));
dynamic viewModel = Shape.ViewModel()
.ContentItems(list)
.Pager(pagerShape)
.ContainerId(model.ContainerId)
.Options(model.Options)
.HasRestriction(hasRestriction)
.ContainerDisplayName(model.ContainerDisplayName)
.ContainerContentType(container.ContentType)
.ContainerItemContentType(hasRestriction ? restrictedContentType : (model.FilterByContentType ?? ""))
.OtherLists(_contentManager.Query<ContainerPart>(VersionOptions.Latest).List()
.Select(part => part.ContentItem)
.Where(item => item != container)
.OrderBy(item => item.As<CommonPart>().VersionPublishedUtc));
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)viewModel);
}
[HttpPost, ActionName("List")]
[FormValueRequired("submit.BulkEdit")]
public ActionResult ListPOST(ContentOptions options, IEnumerable<int> itemIds, int? targetContainerId, string returnUrl) {
if (itemIds != null) {
switch (options.BulkAction) {
case ContentsBulkAction.None:
break;
case ContentsBulkAction.PublishNow:
if (!BulkPublishNow(itemIds)) {
return new HttpUnauthorizedResult();
}
break;
case ContentsBulkAction.Unpublish:
if (!BulkUnpublish(itemIds)) {
return new HttpUnauthorizedResult();
}
break;
case ContentsBulkAction.Remove:
if (!BulkRemove(itemIds)) {
return new HttpUnauthorizedResult();
}
break;
case ContentsBulkAction.RemoveFromList:
if (!BulkRemoveFromList(itemIds)) {
return new HttpUnauthorizedResult();
}
break;
case ContentsBulkAction.MoveToList:
if (!BulkMoveToList(itemIds, targetContainerId)) {
return new HttpUnauthorizedResult();
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
return this.RedirectLocal(returnUrl, () => RedirectToAction("List"));
}
private bool BulkMoveToList(IEnumerable<int> itemIds, int? targetContainerId) {
if (!targetContainerId.HasValue) {
Services.Notifier.Information(T("Please select the list to move the items to."));
return true;
}
var id = targetContainerId.Value;
var targetContainer = _contentManager.Get<ContainerPart>(id);
if (targetContainer == null) {
Services.Notifier.Information(T("Please select the list to move the items to."));
return true;
}
var itemContentType = targetContainer.Record.ItemContentType;
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
if (!Services.Authorizer.Authorize(Permissions.EditContent, item, T("Couldn't move selected content."))) {
return false;
}
// ensure the item can be in that container.
if (!string.IsNullOrEmpty(itemContentType) && item.ContentType != itemContentType) {
Services.Notifier.Information(T("One or more items could not be moved to the '{0}' list because it is restricted to containing items of type '{1}'.", _contentManager.GetItemMetadata(item).DisplayText, itemContentType));
return true; // todo: transactions
}
item.As<CommonPart>().Record.Container = targetContainer.ContentItem.Record;
}
Services.Notifier.Information(T("Content successfully moved to <a href=\"{0}\">{1}</a>.",
Url.Action("List", new { containerId = targetContainerId }), _contentManager.GetItemMetadata(targetContainer).DisplayText));
return true;
}
private bool BulkRemoveFromList(IEnumerable<int> itemIds) {
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
if (!Services.Authorizer.Authorize(Permissions.EditContent, item, T("Couldn't remove selected content from the list."))) {
return false;
}
item.As<CommonPart>().Record.Container = null;
}
Services.Notifier.Information(T("Content successfully removed from the list."));
return true;
}
private bool BulkRemove(IEnumerable<int> itemIds) {
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
if (!Services.Authorizer.Authorize(Permissions.DeleteContent, item, T("Couldn't remove selected content."))) {
return false;
}
_contentManager.Remove(item);
}
Services.Notifier.Information(T("Content successfully removed."));
return true;
}
private bool BulkUnpublish(IEnumerable<int> itemIds) {
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
if (!Services.Authorizer.Authorize(Permissions.PublishContent, item, T("Couldn't unpublish selected content."))) {
return false;
}
_contentManager.Unpublish(item);
}
Services.Notifier.Information(T("Content successfully unpublished."));
return true;
}
private bool BulkPublishNow(IEnumerable<int> itemIds) {
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
if (!Services.Authorizer.Authorize(Permissions.PublishContent, item, T("Couldn't publish selected content.")))
return false;
_contentManager.Publish(item);
}
Services.Notifier.Information(T("Content successfully published."));
return true;
}
[HttpPost, ActionName("List")]
[FormValueRequired("submit.Filter")]
public ActionResult ListFilterPOST(ContentOptions options) {
var routeValues = ControllerContext.RouteData.Values;
if (options != null) {
routeValues["Options.OrderBy"] = options.OrderBy;
if (GetContainableTypes().Any(ctd => string.Equals(ctd.Name, options.SelectedFilter, StringComparison.OrdinalIgnoreCase))) {
routeValues["filterByContentType"] = options.SelectedFilter;
}
else {
routeValues.Remove("filterByContentType");
}
}
return RedirectToAction("List", routeValues);
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Containers.Models;
using Orchard.Data;
namespace Orchard.Lists.Handlers {
public class ContainerPartHandler : ContentHandler {
public ContainerPartHandler() {
}
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
var container = context.ContentItem.As<ContainerPart>();
if (container == null)
return;
// containers link to their contents in admin screens
context.Metadata.AdminRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Lists"},
{"Controller", "Admin"},
{"Action", "List"},
{"containerId", container.Id}
};
}
}
}

View File

@@ -39,6 +39,7 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
@@ -47,7 +48,11 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Handlers\ContainerPartHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Routes.cs" />
<Content Include="Scripts\orchard-lists-admin.js" />
<Compile Include="ViewModels\ListContentsViewModel.cs" />
<Content Include="Module.txt" />
</ItemGroup>
<ItemGroup>
@@ -61,6 +66,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Migrations.cs" />
</ItemGroup>
<ItemGroup>
@@ -76,7 +82,21 @@
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Views\" />
<Content Include="Placement.info" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Admin\List.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Parts.Container.Contained.SummaryAdmin.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Parts.Container.Manage.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Scripts\Web.config">
<SubType>Designer</SubType>
</Content>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

View File

@@ -0,0 +1,9 @@
<Placement>
<!-- available display shapes -->
<!--
Parts_Container_Contained_SummaryAdmin
-->
<Match DisplayType="SummaryAdmin">
<Place Parts_Container_Contained_SummaryAdmin="Actions:10"/>
</Match>
</Placement>

View File

@@ -3,7 +3,7 @@ using System.Web.Mvc;
using System.Web.Routing;
using Orchard.Mvc.Routes;
namespace Orchard.Core.Contents {
namespace Orchard.Lists {
public class Routes : IRouteProvider {
public void GetRoutes(ICollection<RouteDescriptor> routes) {
foreach (RouteDescriptor routeDescriptor in GetRoutes()) {
@@ -16,36 +16,36 @@ namespace Orchard.Core.Contents {
new RouteDescriptor {
Priority = 5,
Route = new Route(
"Admin/Contents/List/{id}/InContainer/{containerId}",
"Admin/Orchard.Lists/{containerId}/{filterByContentType}",
new RouteValueDictionary {
{"area", "Contents"},
{"controller", "Admin"},
{"action", "List"}
{"action", "List"},
{"filterByContentType", ""}
},
new RouteValueDictionary {
{"id", @"\w+"},
new RouteValueDictionary{
{"filterByContentType", @"\w+"},
{"containerId", @"\d+"}
},
new RouteValueDictionary {
{"area", "Contents"}
{"area", "Orchard.Lists"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Priority = 5,
Route = new Route(
"Admin/Contents/List/InContainer/{containerId}",
"Admin/Orchard.Lists/{containerId}",
new RouteValueDictionary {
{"area", "Contents"},
{"area", "Orchard.Lists"},
{"controller", "Admin"},
{"action", "List"},
{"id", ""}
{"action", "List"}
},
new RouteValueDictionary{
new RouteValueDictionary {
{"containerId", @"\d+"}
},
new RouteValueDictionary {
{"area", "Contents"}
{"area", "Orchard.Lists"}
},
new MvcRouteHandler())
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.web>
<httpHandlers>
<!-- iis6 - for any request in this location, return via managed static file handler -->
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers accessPolicy="Script,Read">
<!--
iis7 - for any request to a file exists on disk, return it via native http module.
accessPolicy 'Script' is to allow for a managed 404 page.
-->
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
</handlers>
</system.webServer>
</configuration>

View File

@@ -0,0 +1,10 @@
jQuery("#publishActions").bind("change", function () {
var value = jQuery(this).val(),
target = jQuery("#TargetContainerId");
if (value === "MoveToList") {
target.css("display", "inline");
}
else {
target.css("display", "none");
}
});

View File

@@ -0,0 +1,53 @@
using System.Collections.Generic;
using Orchard.ContentManagement;
namespace Orchard.Lists.ViewModels {
public class ListContentsViewModel {
public ListContentsViewModel() {
Options = new ContentOptions();
}
public string FilterByContentType { get; set; }
public int? ContainerId { get; set; }
public string ContainerDisplayName { get; set; }
public int? Page { get; set; }
public IList<Entry> Entries { get; set; }
public ContentOptions Options { get; set; }
#region Nested type: Entry
public class Entry {
public ContentItem ContentItem { get; set; }
public ContentItemMetadata ContentItemMetadata { get; set; }
}
#endregion
}
public class ContentOptions {
public ContentOptions() {
OrderBy = ContentsOrder.Modified;
BulkAction = ContentsBulkAction.None;
}
public string SelectedFilter { get; set; }
public IEnumerable<KeyValuePair<string, string>> FilterOptions { get; set; }
public ContentsOrder OrderBy { get; set; }
public ContentsBulkAction BulkAction { get; set; }
}
public enum ContentsOrder {
Modified,
Published,
Created
}
public enum ContentsBulkAction {
None,
PublishNow,
Unpublish,
Remove,
RemoveFromList,
MoveToList
}
}

View File

@@ -0,0 +1,64 @@
@using Orchard.Lists.ViewModels;
@{
Script.Include("orchard-lists-admin.js");
string createLinkText = string.IsNullOrEmpty(Model.ContainerItemContentType) ? T("Create New Content").ToString() : T("Create New {0}", Model.ContainerItemContentType).ToString();
Layout.Title = T("Manage Content for {0}", Model.ContainerDisplayName);
var lists = ((IEnumerable<dynamic>)Model.OtherLists).Select(
contentItem => new SelectListItem {
Text = contentItem.ContentType + ": " + contentItem.ContentManager.GetItemMetadata(contentItem).DisplayText,
Value = contentItem.Id.ToString(System.Globalization.CultureInfo.InvariantCulture)
}).ToList();
lists.Insert(0, new SelectListItem { Text = T("Move to...").ToString(), Value = "" });
}
<style type="text/css">
.dyn #TargetContainerId {
display: none /* todo: move to css file */
}
</style>
<div>&nbsp;</div>
@Display.Parts_Container_Manage(ContainerDisplayName: Model.ContainerDisplayName, ContainerContentType: Model.ContainerContentType, ContainerId: Model.ContainerId)
<div class="manage">
@Html.ActionLink(createLinkText, "Create", new { Area = "Contents", Id = (string)Model.Options.SelectedFilter, ContainerId = Model.ContainerId, ReturnUrl = Html.ViewContext.HttpContext.Request.RawUrl }, new { @class = "button primaryAction" })
</div>
@using (Html.BeginFormAntiForgeryPost()) {
<fieldset class="bulk-actions">
<label for="publishActions">@T("Actions:")</label>
<select id="publishActions" name="Options.BulkAction">
@Html.SelectOption((ContentsBulkAction)Model.Options.BulkAction, ContentsBulkAction.None, T("Choose action...").ToString())
@Html.SelectOption((ContentsBulkAction)Model.Options.BulkAction, ContentsBulkAction.PublishNow, T("Publish Now").ToString())
@Html.SelectOption((ContentsBulkAction)Model.Options.BulkAction, ContentsBulkAction.Unpublish, T("Unpublish").ToString())
@Html.SelectOption((ContentsBulkAction)Model.Options.BulkAction, ContentsBulkAction.Remove, T("Delete").ToString())
@Html.SelectOption((ContentsBulkAction)Model.Options.BulkAction, ContentsBulkAction.RemoveFromList, T("Remove from List").ToString())
@Html.SelectOption((ContentsBulkAction)Model.Options.BulkAction, ContentsBulkAction.MoveToList, T("Move to List...").ToString())
</select>
@Html.DropDownList("TargetContainerId", lists, new { id = "TargetContainerId" })
<button type="submit" name="submit.BulkEdit" value="yes">@T("Apply")</button>
</fieldset>
<fieldset class="bulk-actions">
@if(!Model.HasRestriction) {
<label for="filterResults" class="bulk-filter">@T("Show")</label>
<select id="filterResults" name="Options.SelectedFilter">
@Html.SelectOption((string)Model.Options.SelectedFilter, "", T("any (show all)").ToString())
@foreach(var filterOption in Model.Options.FilterOptions) {
@Html.SelectOption((string)Model.Options.SelectedFilter, (string)filterOption.Key, (string)filterOption.Value)
}
</select>
}
<label for="orderResults" class="bulk-order">@T("Ordered by")</label>
<select id="orderResults" name="Options.OrderBy">
@Html.SelectOption((ContentsOrder)Model.Options.OrderBy, ContentsOrder.Created, T("recently created").ToString())
@Html.SelectOption((ContentsOrder)Model.Options.OrderBy, ContentsOrder.Modified, T("recently modified").ToString())
@Html.SelectOption((ContentsOrder)Model.Options.OrderBy, ContentsOrder.Published, T("recently published").ToString())
</select>
<button type="submit" name="submit.Filter" value="yes please">@T("Apply")</button>
</fieldset>
<fieldset class="contentItems bulk-items">
@Display(Model.ContentItems)
</fieldset>
@Display(Model.Pager)
}

View File

@@ -5,5 +5,5 @@
ContentPart contentPart = Model.ContentPart;
}
@if (contentPart.Is<ContainerPart>()) {
@Html.Link(T("Contained Items").Text, Url.Action("List", "Admin", new { area = "Contents", containerId = contentPart.Id }))@T(" | ")
@Html.Link(T("Contained Items").Text, Url.Action("List", "Admin", new { area = "Orchard.Lists", containerId = contentPart.Id }))@T(" | ")
}

View File

@@ -0,0 +1,8 @@
<div class="item-properties actions">
<p>
@Html.ActionLink(T("Show Other Lists").ToString(), "List", new { Area = "Contents", Id = Model.ContainerContentType }) |
@Html.ActionLink(T("Show Orphaned Content Items").ToString(), "Orphaned") |
@Html.ActionLink(T("{0} Properties", (string)Model.ContainerContentType).ToString(), "Edit", new { Area = "Contents", Id = Model.ContainerId })
</p>
</div>