Merge branch '1.10.x' into dev

# Conflicts:
#	src/Orchard.Web/Core/Contents/Controllers/AdminController.cs
#	src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js
This commit is contained in:
Benedek Farkas 2019-08-13 17:38:13 +02:00
commit bbc86d38cd
33 changed files with 587 additions and 264 deletions

View File

@ -30,7 +30,11 @@ namespace Orchard.Core.Common {
.Column<DateTime>("PublishedUtc") .Column<DateTime>("PublishedUtc")
.Column<DateTime>("ModifiedUtc") .Column<DateTime>("ModifiedUtc")
.Column<int>("Container_id") .Column<int>("Container_id")
); ).AlterTable(nameof(CommonPartRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.CreatedUtc)}", nameof(CommonPartRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.ModifiedUtc)}", nameof(CommonPartRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.PublishedUtc)}", nameof(CommonPartRecord.PublishedUtc));
});
SchemaBuilder.CreateTable("CommonPartVersionRecord", SchemaBuilder.CreateTable("CommonPartVersionRecord",
table => table table => table
@ -39,7 +43,11 @@ namespace Orchard.Core.Common {
.Column<DateTime>("PublishedUtc") .Column<DateTime>("PublishedUtc")
.Column<DateTime>("ModifiedUtc") .Column<DateTime>("ModifiedUtc")
.Column<string>("ModifiedBy") .Column<string>("ModifiedBy")
); ).AlterTable(nameof(CommonPartVersionRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.CreatedUtc)}", nameof(CommonPartVersionRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.ModifiedUtc)}", nameof(CommonPartVersionRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.PublishedUtc)}", nameof(CommonPartVersionRecord.PublishedUtc));
});
SchemaBuilder.CreateTable("IdentityPartRecord", SchemaBuilder.CreateTable("IdentityPartRecord",
table => table table => table
@ -59,7 +67,7 @@ namespace Orchard.Core.Common {
.Attachable() .Attachable()
.WithDescription("Automatically generates a unique identity for the content item, which is required in import/export scenarios where one content item references another.")); .WithDescription("Automatically generates a unique identity for the content item, which is required in import/export scenarios where one content item references another."));
return 5; return 6;
} }
public int UpdateFrom1() { public int UpdateFrom1() {
@ -112,5 +120,21 @@ namespace Orchard.Core.Common {
SchemaBuilder.AlterTable("CommonPartVersionRecord", table => table.AddColumn<string>("ModifiedBy", command => command.Nullable())); SchemaBuilder.AlterTable("CommonPartVersionRecord", table => table.AddColumn<string>("ModifiedBy", command => command.Nullable()));
return 5; return 5;
} }
public int UpdateFrom5() {
SchemaBuilder.AlterTable(nameof(CommonPartRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.CreatedUtc)}", nameof(CommonPartRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.ModifiedUtc)}", nameof(CommonPartRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.PublishedUtc)}", nameof(CommonPartRecord.PublishedUtc));
});
SchemaBuilder.AlterTable(nameof(CommonPartVersionRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.CreatedUtc)}", nameof(CommonPartVersionRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.ModifiedUtc)}", nameof(CommonPartVersionRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.PublishedUtc)}", nameof(CommonPartVersionRecord.PublishedUtc));
});
return 6;
}
} }
} }

View File

@ -14,20 +14,19 @@ using Orchard.Core.Containers.Models;
using Orchard.Core.Contents.Settings; using Orchard.Core.Contents.Settings;
using Orchard.Core.Contents.ViewModels; using Orchard.Core.Contents.ViewModels;
using Orchard.Data; using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Localization.Services;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Mvc.Extensions; using Orchard.Mvc.Extensions;
using Orchard.Mvc.Html; using Orchard.Mvc.Html;
using Orchard.Settings;
using Orchard.UI.Navigation; using Orchard.UI.Navigation;
using Orchard.UI.Notify; using Orchard.UI.Notify;
using Orchard.Settings;
using Orchard.Utility.Extensions; using Orchard.Utility.Extensions;
using Orchard.Localization.Services;
namespace Orchard.Core.Contents.Controllers { namespace Orchard.Core.Contents.Controllers {
[ValidateInput(false)] [ValidateInput(false)]
public class AdminController : Controller, IUpdateModel { public class AdminController : ContentControllerBase, IUpdateModel {
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;
private readonly IContentDefinitionManager _contentDefinitionManager; private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly ITransactionManager _transactionManager; private readonly ITransactionManager _transactionManager;
@ -37,24 +36,21 @@ namespace Orchard.Core.Contents.Controllers {
public AdminController( public AdminController(
IOrchardServices orchardServices, IOrchardServices orchardServices,
IContentManager contentManager,
IContentDefinitionManager contentDefinitionManager, IContentDefinitionManager contentDefinitionManager,
ITransactionManager transactionManager,
ISiteService siteService, ISiteService siteService,
IShapeFactory shapeFactory,
ICultureManager cultureManager, ICultureManager cultureManager,
ICultureFilter cultureFilter) { ICultureFilter cultureFilter) : base(orchardServices.ContentManager) {
Services = orchardServices; Services = orchardServices;
_contentManager = contentManager; _contentManager = orchardServices.ContentManager;
_transactionManager = orchardServices.TransactionManager;
_contentDefinitionManager = contentDefinitionManager; _contentDefinitionManager = contentDefinitionManager;
_transactionManager = transactionManager;
_siteService = siteService; _siteService = siteService;
_cultureManager = cultureManager; _cultureManager = cultureManager;
_cultureFilter = cultureFilter; _cultureFilter = cultureFilter;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
Shape = shapeFactory; Shape = orchardServices.New;
} }
dynamic Shape { get; set; } dynamic Shape { get; set; }
@ -248,6 +244,11 @@ namespace Orchard.Core.Contents.Controllers {
var contentItem = _contentManager.New(id); var contentItem = _contentManager.New(id);
var customRouteRedirection = GetCustomContentItemRouteRedirection(contentItem, ContentItemRoute.Create);
if (customRouteRedirection != null) {
return customRouteRedirection;
}
if (!Services.Authorizer.Authorize(Permissions.CreateContent, contentItem, T("Cannot create content"))) if (!Services.Authorizer.Authorize(Permissions.CreateContent, contentItem, T("Cannot create content")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
@ -323,6 +324,11 @@ namespace Orchard.Core.Contents.Controllers {
public ActionResult Edit(int id) { public ActionResult Edit(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Latest); var contentItem = _contentManager.Get(id, VersionOptions.Latest);
var customRouteRedirection = GetCustomContentItemRouteRedirection(contentItem, ContentItemRoute.Editor);
if (customRouteRedirection != null) {
return customRouteRedirection;
}
if (contentItem == null) if (contentItem == null)
return HttpNotFound(); return HttpNotFound();
@ -416,6 +422,10 @@ namespace Orchard.Core.Contents.Controllers {
// pass a dummy content to the authorization check to check for "own" variations // pass a dummy content to the authorization check to check for "own" variations
var dummyContent = _contentManager.New(originalContentItem.ContentType); var dummyContent = _contentManager.New(originalContentItem.ContentType);
if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("You do not have permission to edit (or create) content.")))
return new HttpUnauthorizedResult();
if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("You do not have permission to edit (or create) content."))) if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("You do not have permission to edit (or create) content.")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();

View File

@ -0,0 +1,52 @@
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.Mvc.Extensions;
namespace Orchard.Core.Contents.Controllers {
public abstract class ContentControllerBase : Controller {
private readonly IContentManager _contentManager;
public ContentControllerBase(IContentManager contentManager) {
_contentManager = contentManager;
}
public RedirectToRouteResult GetCustomContentItemRouteRedirection(IContent content, ContentItemRoute contentItemRoute) {
if (content == null) return null;
var itemMetadata = _contentManager.GetItemMetadata(content);
var currentRoute = RouteData.Values;
bool isCustomRoute(RouteValueDictionary routeValues) =>
!currentRoute.ToRouteString().Equals(routeValues.ToRouteString(), StringComparison.InvariantCultureIgnoreCase);
switch (contentItemRoute) {
case ContentItemRoute.Admin:
if (isCustomRoute(itemMetadata.AdminRouteValues))
return RedirectToRoute(itemMetadata.AdminRouteValues);
break;
case ContentItemRoute.Editor:
if (isCustomRoute(itemMetadata.EditorRouteValues))
return RedirectToRoute(itemMetadata.EditorRouteValues);
break;
case ContentItemRoute.Create:
if (isCustomRoute(itemMetadata.CreateRouteValues))
return RedirectToRoute(itemMetadata.CreateRouteValues);
break;
case ContentItemRoute.Display:
if (isCustomRoute(itemMetadata.DisplayRouteValues))
return RedirectToRoute(itemMetadata.DisplayRouteValues);
break;
}
return null;
}
}
}

View File

@ -1,28 +1,25 @@
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Mvc; using Orchard.Mvc;
using Orchard.Themes; using Orchard.Themes;
namespace Orchard.Core.Contents.Controllers { namespace Orchard.Core.Contents.Controllers {
[Themed] [Themed]
public class ItemController : Controller { public class ItemController : ContentControllerBase {
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;
private readonly IHttpContextAccessor _hca; private readonly IHttpContextAccessor _hca;
public ItemController(IContentManager contentManager, public ItemController(
IShapeFactory shapeFactory, IOrchardServices orchardServices,
IOrchardServices services, IHttpContextAccessor hca) : base(orchardServices.ContentManager) {
IHttpContextAccessor hca) { _contentManager = orchardServices.ContentManager;
_contentManager = contentManager;
_hca = hca; _hca = hca;
Shape = shapeFactory; Services = orchardServices;
Services = services;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
dynamic Shape { get; set; }
public IOrchardServices Services { get; private set; } public IOrchardServices Services { get; private set; }
public Localizer T { get; set; } public Localizer T { get; set; }
@ -36,16 +33,21 @@ namespace Orchard.Core.Contents.Controllers {
var contentItem = _contentManager.Get(id.Value, VersionOptions.Published); var contentItem = _contentManager.Get(id.Value, VersionOptions.Published);
var customRouteRedirection = GetCustomContentItemRouteRedirection(contentItem, ContentItemRoute.Display);
if (customRouteRedirection != null) {
return customRouteRedirection;
}
if (contentItem == null) if (contentItem == null)
return HttpNotFound(); return HttpNotFound();
if (!Services.Authorizer.Authorize(Permissions.ViewContent, contentItem, T("Cannot view content"))) { if (!Services.Authorizer.Authorize(Permissions.ViewContent, contentItem, T("Cannot view content"))) {
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
} }
var model = _contentManager.BuildDisplay(contentItem); var model = _contentManager.BuildDisplay(contentItem);
if (_hca.Current().Request.IsAjaxRequest()) { if (_hca.Current().Request.IsAjaxRequest()) {
return new ShapePartialResult(this,model); return new ShapePartialResult(this, model);
} }
return View(model); return View(model);

View File

@ -1,5 +1,26 @@
@{ Layout.Title = T("Create New Content").ToString(); } @using Orchard;
@using Orchard.ContentManagement;
@using Orchard.Core.Contents;
@{
IOrchardServices _orchardServices;
WorkContext.TryResolve<IOrchardServices>(out _orchardServices);
Layout.Title = T("Create New Content");
}
@foreach (var type in Model.ContentTypes) { @foreach (var type in Model.ContentTypes) {
<p>@Html.ActionLink((string)type.DisplayName, "Create", new { Area = "Contents", Id = (string)type.Name, ContainerId = Model.ContainerId, ReturnUrl = Request.QueryString["ReturnUrl"] })</p> var content = _orchardServices.ContentManager.New(type.Name);
if (Authorizer.Authorize(Permissions.CreateContent, content)) {
ContentItemMetadata metadata = _orchardServices.ContentManager.GetItemMetadata(content);
RouteValueDictionary createRouteValues = metadata.CreateRouteValues;
createRouteValues.Add("ContainerId", Model.ContainerId);
createRouteValues.Add("ReturnUrl", Request.QueryString["ReturnUrl"]);
var url = Url.RouteUrl(createRouteValues);
<p><a href="@url">@type.DisplayName</a></p>
}
} }

View File

@ -1,13 +1,18 @@
@using Orchard.Core.Contents; @using Orchard;
@using Orchard.ContentManagement;
@using Orchard.Core.Contents;
@using Orchard.Core.Contents.ViewModels; @using Orchard.Core.Contents.ViewModels;
@using Orchard.Security; @using Orchard.Security;
@using Orchard.Security.Permissions;
@{ @{
IOrchardServices _orchardServices;
WorkContext.TryResolve<IOrchardServices>(out _orchardServices);
var typeDisplayName = Model.TypeDisplayName; var typeDisplayName = Model.TypeDisplayName;
var pageTitle = T("Manage Content"); var pageTitle = T("Manage Content");
var createLinkText = T("Create New Content"); var createLinkText = T("Create New Content");
// if no specific type is selected, we assume we should show the "Create" button // if no specific type is selected, we assume we should show the "Create" button
var showCreateContentButton = string.IsNullOrWhiteSpace(typeDisplayName); var showCreateContentButton = string.IsNullOrWhiteSpace(typeDisplayName);
IAuthorizationService _authorizationService; IAuthorizationService _authorizationService;
WorkContext.TryResolve<IAuthorizationService>(out _authorizationService); WorkContext.TryResolve<IAuthorizationService>(out _authorizationService);
@ -26,9 +31,19 @@
Layout.Title = pageTitle.Text; Layout.Title = pageTitle.Text;
} }
@if (showCreateContentButton) { @if (showCreateContentButton) {
<div class="manage"> <div class="manage">
@Html.ActionLink(createLinkText.Text, "Create", new { Area = "Contents", Id = (string)Model.Options.SelectedFilter }, new { @class = "button primaryAction" }) @{
if (!String.IsNullOrWhiteSpace((string)Model.Options.SelectedFilter)) {
var content = _orchardServices.ContentManager.New(Model.Options.SelectedFilter);
ContentItemMetadata metadata = _orchardServices.ContentManager.GetItemMetadata(content);
var url = Url.RouteUrl(metadata.CreateRouteValues);
<a class="button primaryAction" href="@url">@createLinkText.Text</a>
} else {
@Html.ActionLink(createLinkText.Text, "Create", new { Area = "Contents", Id = (string)Model.Options.SelectedFilter }, new { @class = "button primaryAction" });
}
}
</div> </div>
} }
@using (Html.BeginFormAntiForgeryPost()) { @using (Html.BeginFormAntiForgeryPost()) {

View File

@ -153,6 +153,7 @@
<Compile Include="Containers\ViewModels\ContainerViewModel.cs" /> <Compile Include="Containers\ViewModels\ContainerViewModel.cs" />
<Compile Include="Containers\ViewModels\ContainerTypePartSettingsViewModel.cs" /> <Compile Include="Containers\ViewModels\ContainerTypePartSettingsViewModel.cs" />
<Compile Include="Containers\ViewModels\ContainerWidgetViewModel.cs" /> <Compile Include="Containers\ViewModels\ContainerWidgetViewModel.cs" />
<Compile Include="Contents\Controllers\ContentControllerBase.cs" />
<Compile Include="Contents\ControlWrapper.cs" /> <Compile Include="Contents\ControlWrapper.cs" />
<Compile Include="Contents\Security\AuthorizationEventHandler.cs" /> <Compile Include="Contents\Security\AuthorizationEventHandler.cs" />
<Compile Include="Common\Services\BbcodeFilter.cs" /> <Compile Include="Common\Services\BbcodeFilter.cs" />

View File

@ -17,88 +17,87 @@ namespace Orchard.Autoroute {
} }
public int Create() { public int Create() {
SchemaBuilder.CreateTable("AutoroutePartRecord", SchemaBuilder.CreateTable("AutoroutePartRecord", table => table
table => table .ContentPartVersionRecord()
.ContentPartVersionRecord() .Column<string>("CustomPattern", c => c.WithLength(2048))
.Column<string>("CustomPattern", c => c.WithLength(2048)) .Column<bool>("UseCustomPattern", c => c.WithDefault(false))
.Column<bool>("UseCustomPattern", c => c.WithDefault(false)) .Column<bool>("UseCulturePattern", c => c.WithDefault(false))
.Column<bool>("UseCulturePattern", c => c.WithDefault(false)) .Column<string>("DisplayAlias", c => c.WithLength(2048)));
.Column<string>("DisplayAlias", c => c.WithLength(2048)));
ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part
.Attachable() .Attachable()
.WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item.")); .WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item."));
SchemaBuilder.AlterTable("AutoroutePartRecord", table => table SchemaBuilder.AlterTable("AutoroutePartRecord", table => table
.CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias") .CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias"));
);
return 4; CreateCulturePatterns();
return 5;
} }
public int UpdateFrom1() { public int UpdateFrom1() {
ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part
.WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item.")); .WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item."));
return 2; return 2;
} }
public int UpdateFrom2() { public int UpdateFrom2() {
SchemaBuilder.AlterTable("AutoroutePartRecord", table => table SchemaBuilder.AlterTable("AutoroutePartRecord", table => table
.CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias") .CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias"));
);
return 3; return 3;
} }
public int UpdateFrom3() { public int UpdateFrom3() {
SchemaBuilder.AlterTable("AutoroutePartRecord", table => table SchemaBuilder.AlterTable("AutoroutePartRecord", table => table
.AddColumn<bool>("UseCulturePattern", c => c.WithDefault(false)) .AddColumn<bool>("UseCulturePattern", c => c.WithDefault(false)));
);
return 4; return 4;
} }
public int UpdateFrom4() { public int UpdateFrom4() {
// Adding some culture neutral patterns if they don't exist CreateCulturePatterns();
var autoroutePartDefinitions = ContentDefinitionManager.ListTypeDefinitions()
.Where(t => t.Parts.Any(p => p.PartDefinition.Name.Equals(typeof(AutoroutePart).Name)))
.Select(s => new { contentTypeName = s.Name, autoroutePart = s.Parts.First(x => x.PartDefinition.Name == "AutoroutePart") });
foreach (var partDefinition in autoroutePartDefinitions) {
var settingsDictionary = partDefinition.autoroutePart.Settings;
var settings = settingsDictionary.GetModel<AutorouteSettings>();
if (!settings.Patterns.Any(x => String.IsNullOrWhiteSpace(x.Culture))) {
string siteCulture = _cultureManager.GetSiteCulture();
List<string> newPatterns = new List<string>();
if (settings.Patterns.Any(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase))) {
var siteCulturePatterns = settings.Patterns.Where(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase)).ToList();
foreach (RoutePattern pattern in siteCulturePatterns) {
newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", pattern.Name, pattern.Pattern, pattern.Description));
}
}
else {
newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", "Title", "{Content.Slug}", "my-title"));
}
if (settingsDictionary.ContainsKey("AutorouteSettings.PatternDefinitions")) {
string oldPatterns = settingsDictionary["AutorouteSettings.PatternDefinitions"];
if (oldPatterns.StartsWith("[") && oldPatterns.EndsWith("]"))
newPatterns.Add(oldPatterns.Substring(1, oldPatterns.Length - 2));
}
ContentDefinitionManager.AlterTypeDefinition(partDefinition.contentTypeName, cfg => cfg
.WithPart("AutoroutePart", builder => builder
.WithSetting("AutorouteSettings.PatternDefinitions", "[" + String.Join(",", newPatterns) + "]")
));
}
}
return 5; return 5;
} }
private void CreateCulturePatterns() {
var autoroutePartDefinitions = ContentDefinitionManager.ListTypeDefinitions()
.Where(type => type.Parts.Any(p => p.PartDefinition.Name == nameof(AutoroutePart)))
.Select(type => new { ContentTypeName = type.Name, AutoroutePart = type.Parts.First(x => x.PartDefinition.Name == nameof(AutoroutePart)) });
foreach (var partDefinition in autoroutePartDefinitions) {
var settingsDictionary = partDefinition.AutoroutePart.Settings;
var settings = settingsDictionary.GetModel<AutorouteSettings>();
if (!settings.Patterns.Any(pattern => string.IsNullOrWhiteSpace(pattern.Culture))) {
var siteCulture = _cultureManager.GetSiteCulture();
List<string> newPatterns = new List<string>();
var siteCulturePatterns = settings.Patterns
.Where(pattern => string.Equals(pattern.Culture, siteCulture, StringComparison.OrdinalIgnoreCase)).ToList();
if (siteCulturePatterns.Any()) {
foreach (RoutePattern pattern in siteCulturePatterns) {
newPatterns.Add($"{{\"Name\":\"{pattern.Name}\",\"Pattern\":\"{pattern.Pattern}\",\"Description\":\"{pattern.Description}\"}}");
}
}
else {
newPatterns.Add("{{\"Name\":\"Title\",\"Pattern\":\"{Content.Slug}\",\"Description\":\"my-title\"}}");
}
if (settingsDictionary.TryGetValue("AutorouteSettings.PatternDefinitions", out var oldPatterns) &&
oldPatterns.StartsWith("[") && oldPatterns.EndsWith("]")) {
newPatterns.Add(oldPatterns.Substring(1, oldPatterns.Length - 2));
}
ContentDefinitionManager.AlterTypeDefinition(partDefinition.ContentTypeName, type => type
.WithPart(nameof(AutoroutePart), builder => builder
.WithSetting("AutorouteSettings.PatternDefinitions", "[" + string.Join(",", newPatterns) + "]")));
}
}
}
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.Blogs.Extensions; using Orchard.Blogs.Extensions;
@ -98,6 +99,18 @@ namespace Orchard.Blogs.Controllers {
return Redirect(Url.BlogPostEdit(blogPost)); return Redirect(Url.BlogPostEdit(blogPost));
} }
public ActionResult CreateWithoutBlog() {
var blogs = _blogService.Get().ToArray();
if (blogs.Count() == 0) {
Services.Notifier.Warning(T("To create a BlogPost you need to create a blog first. You have been redirected to the Blog creation page."));
return RedirectToAction("Create", "BlogAdmin", new { area = "Orchard.Blogs" });
} else {
Services.Notifier.Warning(T("To create a BlogPost you need to choose a blog first. You have been redirected to the Blog selection page."));
return RedirectToAction("List", "BlogAdmin", new { area = "Orchard.Blogs" });
}
}
//todo: the content shape template has extra bits that the core contents module does not (remove draft functionality) //todo: the content shape template has extra bits that the core contents module does not (remove draft functionality)
//todo: - move this extra functionality there or somewhere else that's appropriate? //todo: - move this extra functionality there or somewhere else that's appropriate?
public ActionResult Edit(int blogId, int postId) { public ActionResult Edit(int blogId, int postId) {

View File

@ -5,13 +5,18 @@ using Orchard.Blogs.Services;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Security;
namespace Orchard.Blogs.Handlers { namespace Orchard.Blogs.Handlers {
public class BlogPostPartHandler : ContentHandler { public class BlogPostPartHandler : ContentHandler {
private readonly IAuthorizationService _authorizationService;
private readonly IBlogService _blogService; private readonly IBlogService _blogService;
private readonly IWorkContextAccessor _workContextAccessor;
public BlogPostPartHandler(IBlogService blogService, IBlogPostService blogPostService, RequestContext requestContext) { public BlogPostPartHandler(IAuthorizationService authorizationService, IBlogService blogService, IBlogPostService blogPostService, RequestContext requestContext, IWorkContextAccessor workContextAccessor) {
_authorizationService = authorizationService;
_blogService = blogService; _blogService = blogService;
_workContextAccessor = workContextAccessor;
OnGetDisplayShape<BlogPostPart>(SetModelProperties); OnGetDisplayShape<BlogPostPart>(SetModelProperties);
OnGetEditorShape<BlogPostPart>(SetModelProperties); OnGetEditorShape<BlogPostPart>(SetModelProperties);
@ -45,8 +50,29 @@ namespace Orchard.Blogs.Handlers {
protected override void GetItemMetadata(GetContentItemMetadataContext context) { protected override void GetItemMetadata(GetContentItemMetadataContext context) {
var blogPost = context.ContentItem.As<BlogPostPart>(); var blogPost = context.ContentItem.As<BlogPostPart>();
if (blogPost == null) {
return;
}
int blogId = 0;
// BlogPart can be null if this is a new Blog Post item. // BlogPart can be null if this is a new Blog Post item.
if (blogPost == null || blogPost.BlogPart == null) { if (blogPost.BlogPart == null) {
var blogs = _blogService.Get().Where(x => _authorizationService.TryCheckAccess(Permissions.MetaListBlogs, _workContextAccessor.GetContext().CurrentUser, x)).ToArray();
if (blogs.Count() == 1) {
var singleBlog = blogs.ElementAt(0);
if (singleBlog != null) blogId = singleBlog.Id;
}
} else {
blogId = blogPost.BlogPart.Id;
}
if (blogId == 0) {
context.Metadata.CreateRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"},
{"Action", "CreateWithoutBlog"}
};
return; return;
} }
@ -54,21 +80,21 @@ namespace Orchard.Blogs.Handlers {
{"Area", "Orchard.Blogs"}, {"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"}, {"Controller", "BlogPostAdmin"},
{"Action", "Create"}, {"Action", "Create"},
{"blogId", blogPost.BlogPart.Id} {"blogId", blogId}
}; };
context.Metadata.EditorRouteValues = new RouteValueDictionary { context.Metadata.EditorRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"}, {"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"}, {"Controller", "BlogPostAdmin"},
{"Action", "Edit"}, {"Action", "Edit"},
{"postId", context.ContentItem.Id}, {"postId", context.ContentItem.Id},
{"blogId", blogPost.BlogPart.Id} {"blogId", blogId}
}; };
context.Metadata.RemoveRouteValues = new RouteValueDictionary { context.Metadata.RemoveRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"}, {"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"}, {"Controller", "BlogPostAdmin"},
{"Action", "Delete"}, {"Action", "Delete"},
{"postId", context.ContentItem.Id}, {"postId", context.ContentItem.Id},
{"blogId", blogPost.BlogPart.Id} {"blogId", blogId}
}; };
} }
} }

View File

@ -88,6 +88,20 @@ namespace Orchard.Blogs {
}, },
new MvcRouteHandler()) new MvcRouteHandler())
}, },
new RouteDescriptor {
Route = new Route(
"Admin/Blogs/Posts/CreateWithoutBlog",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "BlogPostAdmin"},
{"action", "CreateWithoutBlog"}
},
new RouteValueDictionary (),
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
new RouteDescriptor { new RouteDescriptor {
Route = new Route( Route = new Route(
"Admin/Blogs/{blogId}/Posts/{postId}/Edit", "Admin/Blogs/{blogId}/Posts/{postId}/Edit",

View File

@ -160,6 +160,7 @@ namespace Orchard.ContentPicker.Controllers {
RouteData.Values["Options.SelectedFilter"] = model.Options.SelectedFilter; RouteData.Values["Options.SelectedFilter"] = model.Options.SelectedFilter;
RouteData.Values["Options.OrderBy"] = model.Options.OrderBy.ToString(); RouteData.Values["Options.OrderBy"] = model.Options.OrderBy.ToString();
RouteData.Values["Options.ContentsStatus"] = model.Options.ContentsStatus.ToString(); RouteData.Values["Options.ContentsStatus"] = model.Options.ContentsStatus.ToString();
RouteData.Values["Options.SelectedCulture"] = model.Options.SelectedCulture;
return new ShapeResult(this, Services.New.ContentPicker().Tab(tab)); return new ShapeResult(this, Services.New.ContentPicker().Tab(tab));
} }

View File

@ -1,12 +1,18 @@
jQuery(function ($) { jQuery(function ($) {
Initialize = function () { Initialize = function () {
$('.content-picker-itemCheck').each(function () {
$('.button.addSelected').on('click', function () { var related = $(this).siblings('.content-picker-item').children('.related');
var selectedItems = $('.content-picker-itemCheck:checked');
var itemsToAdd = new Array(); if (window.sessionStorage.getItem(related.data("id")) != null) {
$.each(selectedItems, function (index, item) { $(this).prop('checked', true);
var related = $(item).siblings('.content-picker-item').children('.related'); }
});
$('.content-picker-itemCheck').change(function () {
var related = $(this).siblings('.content-picker-item').children('.related');
if (this.checked) {
var data = { var data = {
id: related.data("id"), id: related.data("id"),
displayText: related.data("display-text"), displayText: related.data("display-text"),
@ -16,13 +22,27 @@
displayLink: related.data("display-link"), displayLink: related.data("display-link"),
published: related.data("published") published: related.data("published")
}; };
return itemsToAdd.push(data);
}); window.sessionStorage.setItem(related.data("id"), JSON.stringify(data));
} else {
window.sessionStorage.removeItem(related.data("id"));
}
});
$('.button.addSelected').on('click', function () {
var itemsToAdd = new Array();
for (var i = 0; i < sessionStorage.length; i++) {
var data = window.sessionStorage.getItem(sessionStorage.key(i));
itemsToAdd.push(JSON.parse(data));
}
window.sessionStorage.clear();
window.opener.jQuery[query("callback")](itemsToAdd); window.opener.jQuery[query("callback")](itemsToAdd);
window.close(); window.close();
}); });
$('.content-picker-SelectAll').on('click', function () { $('.content-picker-SelectAll').on('click', function () {
$('.content-picker-itemCheck').prop('checked', $(this).prop("checked")); $('.content-picker-itemCheck').prop('checked', $(this).prop("checked"));
$('.content-picker-itemCheck').change();
}); });
}; };

View File

@ -16,7 +16,7 @@
var fieldName = Model.FieldName; var fieldName = Model.FieldName;
var baseUrl = Url.Content("~/") + WorkContext.Resolve<ShellSettings>().RequestUrlPrefix; var baseUrl = Url.Content("~/") + WorkContext.Resolve<ShellSettings>().RequestUrlPrefix;
var types = String.Join(",", (IEnumerable<string>)Model.Types ?? Enumerable.Empty<string>()); var types = String.Join(",", (IEnumerable<string>)Model.Types ?? Enumerable.Empty<string>());
} }
<fieldset class="content-picker-field" <fieldset class="content-picker-field"
data-required="@required.ToString().ToLower()" data-required="@required.ToString().ToLower()"
@ -50,7 +50,7 @@
<tr> <tr>
<td>&nbsp;</td> <td>&nbsp;</td>
<td> <td>
<span data-id="@contentItem.Id" data-fieldid="@idsFieldId" class="content-picker-item">@Html.ItemAdminLink(contentItem) @if (!contentItem.HasPublished()){<text> - </text>@T("Not Published")}</span> <span data-id="@contentItem.Id" data-fieldid="@idsFieldId" class="content-picker-item">@Html.ItemAdminLink(null, contentItem, new { ReturnUrl = @Request.Url.ToString()}) @if (!contentItem.HasPublished()){<text> - </text>@T("Not Published")}</span>
</td> </td>
<td> <td>
<span data-id="@contentItem.Id" class="content-picker-remove button grey">@T("Remove")</span> <span data-id="@contentItem.Id" class="content-picker-remove button grey">@T("Remove")</span>

View File

@ -5,7 +5,9 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.DisplayManagement; using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors; using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath; using Orchard.FileSystems.VirtualPath;
using Orchard.Mvc.Routes;
using Orchard.UI.Zones; using Orchard.UI.Zones;
namespace Orchard.Layouts.Services { namespace Orchard.Layouts.Services {
@ -30,9 +32,9 @@ namespace Orchard.Layouts.Services {
_requestContext = requestContext; _requestContext = requestContext;
_virtualPathProvider = virtualPathProvider; _virtualPathProvider = virtualPathProvider;
_workContextAccessor = workContextAccessor; _workContextAccessor = workContextAccessor;
} }
public abstract UrlPrefix TenantUrlPrefix { get; }
public abstract string DefaultStereotype { get; } public abstract string DefaultStereotype { get; }
public BuildDisplayContext BuildDisplayContext(IContent content, string displayType, string groupId) { public BuildDisplayContext BuildDisplayContext(IContent content, string displayType, string groupId) {
@ -145,7 +147,12 @@ namespace Orchard.Layouts.Services {
/// Gets the current app-relative path, i.e. ~/my-blog/foo. /// Gets the current app-relative path, i.e. ~/my-blog/foo.
/// </summary> /// </summary>
private string GetPath() { private string GetPath() {
return VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path)); var appRelativePath = _virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path);
// If the tenant has a prefix, we strip the tenant prefix away.
if (TenantUrlPrefix != null)
appRelativePath = TenantUrlPrefix.RemoveLeadingSegments(appRelativePath);
return VirtualPathUtility.AppendTrailingSlash(appRelativePath);
} }
} }
} }

View File

@ -6,24 +6,39 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.DisplayManagement; using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors; using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath; using Orchard.FileSystems.VirtualPath;
using Orchard.Mvc.Routes;
namespace Orchard.Layouts.Services { namespace Orchard.Layouts.Services {
public class ContentFieldDisplay : ContentDisplayBase, IContentFieldDisplay { public class ContentFieldDisplay : ContentDisplayBase, IContentFieldDisplay {
private readonly IEnumerable<IContentFieldDriver> _contentFieldDrivers; private readonly IEnumerable<IContentFieldDriver> _contentFieldDrivers;
private readonly ShellSettings _shellSettings;
public ContentFieldDisplay( public ContentFieldDisplay(
IShapeFactory shapeFactory, IShapeFactory shapeFactory,
Lazy<IShapeTableLocator> shapeTableLocator, Lazy<IShapeTableLocator> shapeTableLocator,
RequestContext requestContext, RequestContext requestContext,
IVirtualPathProvider virtualPathProvider, IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor, IWorkContextAccessor workContextAccessor,
IEnumerable<IContentFieldDriver> contentFieldDrivers) ShellSettings shellSettings,
IEnumerable<IContentFieldDriver> contentFieldDrivers)
: base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) { : base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) {
_shellSettings = shellSettings;
_contentFieldDrivers = contentFieldDrivers; _contentFieldDrivers = contentFieldDrivers;
} }
public override UrlPrefix TenantUrlPrefix {
get {
if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) {
return new UrlPrefix(_shellSettings.RequestUrlPrefix);
}
else {
return null;
}
}
}
public override string DefaultStereotype { public override string DefaultStereotype {
get { return "ContentField"; } get { return "ContentField"; }
} }
@ -63,7 +78,7 @@ namespace Orchard.Layouts.Services {
if (result != null) if (result != null)
result.Apply(context); result.Apply(context);
}, Logger); }, Logger);
return context.Shape; return context.Shape;
} }

View File

@ -6,23 +6,38 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.DisplayManagement; using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors; using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath; using Orchard.FileSystems.VirtualPath;
using Orchard.Mvc.Routes;
namespace Orchard.Layouts.Services { namespace Orchard.Layouts.Services {
public class ContentPartDisplay : ContentDisplayBase, IContentPartDisplay { public class ContentPartDisplay : ContentDisplayBase, IContentPartDisplay {
private readonly IEnumerable<IContentPartDriver> _contentPartDrivers; private readonly IEnumerable<IContentPartDriver> _contentPartDrivers;
private readonly ShellSettings _shellSettings;
public ContentPartDisplay( public ContentPartDisplay(
IShapeFactory shapeFactory, IShapeFactory shapeFactory,
Lazy<IShapeTableLocator> shapeTableLocator, Lazy<IShapeTableLocator> shapeTableLocator,
RequestContext requestContext, RequestContext requestContext,
IVirtualPathProvider virtualPathProvider, IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor, IWorkContextAccessor workContextAccessor,
ShellSettings shellSettings,
IEnumerable<IContentPartDriver> contentPartDrivers) IEnumerable<IContentPartDriver> contentPartDrivers)
: base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) { : base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) {
_shellSettings = shellSettings;
_contentPartDrivers = contentPartDrivers; _contentPartDrivers = contentPartDrivers;
} }
public override UrlPrefix TenantUrlPrefix {
get {
if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) {
return new UrlPrefix(_shellSettings.RequestUrlPrefix);
}
else {
return null;
}
}
}
public override string DefaultStereotype { public override string DefaultStereotype {
get { return "ContentPart"; } get { return "ContentPart"; }

View File

@ -1,4 +1,6 @@
@{ @using System.Globalization
@{
var currentCulture = WorkContext.CurrentCulture; var currentCulture = WorkContext.CurrentCulture;
var supportedCultures = (IList<string>)Model.SupportedCultures; var supportedCultures = (IList<string>)Model.SupportedCultures;
} }
@ -6,15 +8,20 @@
<div id="culture-selection"> <div id="culture-selection">
<ul> <ul>
@foreach (var supportedCulture in supportedCultures) { @foreach (var supportedCulture in supportedCultures) {
var url = Url.Action("ChangeCulture", "AdminCultureSelector", new { area = "Orchard.Localization", culture = supportedCulture, returnUrl = Html.ViewContext.HttpContext.Request.RawUrl }); var culture = CultureInfo.GetCultureInfo(supportedCulture);
<li> if (culture is object)
@if (supportedCulture.Equals(currentCulture)) { {
<a href="@url">@T("{0} (current)", supportedCulture)</a> var url = Url.Action("ChangeCulture", "AdminCultureSelector", new { area = "Orchard.Localization", culture = supportedCulture, returnUrl = Html.ViewContext.HttpContext.Request.RawUrl });
} else {
<a href="@url">@supportedCulture</a> <li>
} @if (supportedCulture.Equals(currentCulture)) {
</li> <a href="@url">@T("{0} (current)", culture.DisplayName)</a>
} else {
<a href="@url">@culture.DisplayName</a>
}
</li>
}
} }
</ul> </ul>
</div> </div>

View File

@ -3,6 +3,7 @@
@using Orchard.ContentManagement @using Orchard.ContentManagement
@using Orchard.ContentManagement.Aspects @using Orchard.ContentManagement.Aspects
@using Orchard.Localization.Services @using Orchard.Localization.Services
@{ @{
var localizableAspects = Enumerable.Empty<ILocalizableAspect>(); var localizableAspects = Enumerable.Empty<ILocalizableAspect>();
var homePage = WorkContext.Resolve<IHomeAliasService>().GetHomePage(); var homePage = WorkContext.Resolve<IHomeAliasService>().GetHomePage();
@ -12,26 +13,24 @@
localizableAspects = localizationService.GetLocalizations(homePage).Concat(new[] { homePage.As<ILocalizableAspect>() }); localizableAspects = localizationService.GetLocalizations(homePage).Concat(new[] { homePage.As<ILocalizableAspect>() });
} }
} }
@if (localizableAspects.Any()) { @if (localizableAspects.Any()) {
<div> <div>
<ul> <ul>
@foreach (var localization in localizableAspects) { @foreach (var localization in localizableAspects.Where(localization => !string.IsNullOrEmpty(localization.Culture))) {
var culture = CultureInfo.GetCultureInfo(localization.Culture);
if (localization.Culture == null) { if (culture is object) {
continue; <li>
@if (localization.Culture.Equals(WorkContext.CurrentCulture, StringComparison.InvariantCultureIgnoreCase)) {
<a href="@Url.ItemDisplayUrl(localization)">@T("{0} (current)", culture.DisplayName)</a>
}
else {
<a href="@Url.ItemDisplayUrl(localization)">@culture.DisplayName</a>
}
</li>
}
} }
</ul>
var culture = CultureInfo.GetCultureInfo(localization.Culture); </div>
<li>
@if (localization.Culture.Equals(WorkContext.CurrentCulture, StringComparison.InvariantCultureIgnoreCase)) {
<a href="@Url.ItemDisplayUrl(localization)">@T("{0} (current)", culture.DisplayName)</a>
}
else {
<a href="@Url.ItemDisplayUrl(localization)">@T("{0}", culture.DisplayName)</a>
}
</li>
}
</ul>
</div>
} }

View File

@ -1,15 +1,15 @@
var enhanceViewModel = function(viewModel) { var enhanceViewModel = function (viewModel) {
// extension point for other modules to alter the view model // extension point for other modules to alter the view model
}; };
var baseViewModel = function() { var baseViewModel = function () {
}; };
$(function () { $(function () {
(function (settings) { (function (settings) {
function attachFolderTitleDropEvent (elements) { function attachFolderTitleDropEvent(elements) {
elements.droppable({ elements.droppable({
accept: function () { accept: function () {
var targetId = $(this).data('term-id'); var targetId = $(this).data('term-id');
@ -47,7 +47,7 @@ $(function () {
folderPath: folderPath, folderPath: folderPath,
mediaItemIds: ids, mediaItemIds: ids,
__RequestVerificationToken: settings.antiForgeryToken __RequestVerificationToken: settings.antiForgeryToken
}, }
}).done(function (result) { }).done(function (result) {
if (result) { if (result) {
if (viewModel.displayed()) { if (viewModel.displayed()) {
@ -67,7 +67,7 @@ $(function () {
}); });
} }
}); });
}; }
var listWidth = $('#media-library-main-list').width(); var listWidth = $('#media-library-main-list').width();
var listHeight = $('#media-library-main-list').height(); var listHeight = $('#media-library-main-list').height();
@ -105,7 +105,7 @@ $(function () {
self.selected = ko.observable(); self.selected = ko.observable();
self.status = ko.observable(''); self.status = ko.observable('');
self.summary = ko.observable(''); self.summary = ko.observable('');
self.cssClass = ko.computed(function() { self.cssClass = ko.computed(function () {
var css = ''; var css = '';
if (self.selected()) { if (self.selected()) {
css += ' selected'; css += ' selected';
@ -118,14 +118,14 @@ $(function () {
return css; return css;
}); });
self.mediaInfos = ko.computed(function () { self.publicationStatus = ko.computed(function () {
var pubStatus = self.data.published ? "" : draftText; var pubStatus = self.data.published ? "" : draftText;
var localization = (self.data.localization != "" ? "(" + self.data.localization + ")" : ""); var localization = (self.data.localization != "" ? "(" + self.data.localization + ")" : "");
return pubStatus + " " + localization; return pubStatus + " " + localization;
}); });
// operations // operations
self.setData = function(value) { self.setData = function (value) {
self.data = value; self.data = value;
}; };
} }
@ -142,6 +142,11 @@ $(function () {
self.focus = ko.observable(); self.focus = ko.observable();
self.results = ko.observableArray(); self.results = ko.observableArray();
self.displayed = ko.observable(); self.displayed = ko.observable();
self.isEveryItemSelected = ko.computed({
read: function () {
return self.selection().length === self.results().length;
}
});
self.mediaItemsCount = 0; self.mediaItemsCount = 0;
self.orderMedia = ko.observableArray(['created']); self.orderMedia = ko.observableArray(['created']);
self.mediaType = ko.observableArray([]); self.mediaType = ko.observableArray([]);
@ -150,7 +155,7 @@ $(function () {
self.mediaFoldersRequestCount = ko.observable(0); self.mediaFoldersRequestCount = ko.observable(0);
self.mediaFoldersPendingRequest = ko.computed({ self.mediaFoldersPendingRequest = ko.computed({
read: function () { read: function () {
return (self.mediaFoldersRequestCount() > 0); return self.mediaFoldersRequestCount() > 0;
}, },
write: function (value) { write: function (value) {
if (value === true) { if (value === true) {
@ -164,7 +169,7 @@ $(function () {
self.mediaPendingRequest = ko.observable(false); self.mediaPendingRequest = ko.observable(false);
self.pendingRequest = ko.computed({ self.pendingRequest = ko.computed({
read: function () { read: function () {
return (self.mediaFoldersPendingRequest() || self.mediaPendingRequest()); return self.mediaFoldersPendingRequest() || self.mediaPendingRequest();
}, },
write: function (value) { write: function (value) {
self.mediaPendingRequest(value); self.mediaPendingRequest(value);
@ -173,7 +178,7 @@ $(function () {
self.getMediaItems = function (count, append) { self.getMediaItems = function (count, append) {
var folderPath = self.displayed() || ''; var folderPath = self.displayed() || '';
if (self.mediaPendingRequest()) { if (self.mediaPendingRequest()) {
return; return;
} }
@ -189,13 +194,12 @@ $(function () {
self.pendingRequest(true); self.pendingRequest(true);
var url = self.loadMediaItemsUrl(folderPath, self.results().length, count, self.orderMedia(), self.mediaType()); var url = self.loadMediaItemsUrl(folderPath, self.results().length, count, self.orderMedia(), self.mediaType());
console.log(url);
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: url, url: url,
cache: false cache: false
}).done(function(data) { }).done(function (data) {
var mediaItems = data.mediaItems; var mediaItems = data.mediaItems;
var mediaItemsFolderPath = data.folderPath; var mediaItemsFolderPath = data.folderPath;
@ -216,35 +220,60 @@ $(function () {
} }
} }
} }
}).fail(function(data) {
self.updateSelectAllText();
}).fail(function (data) {
console.error(data); console.error(data);
}).always(function() { }).always(function () {
self.pendingRequest(false); self.pendingRequest(false);
}); });
}; };
self.clearSelection = function() { self.updateSelectAllText = function () {
var element = $("#select-all-button");
element.html(self.isEveryItemSelected() ? element.data("select-none-text") : element.data("select-all-text"));
};
self.updateAllSelection = function () {
if (self.isEveryItemSelected()) {
self.clearSelection();
}
else {
self.selectAll();
}
self.updateSelectAllText();
};
self.selectAll = function () {
self.results().forEach(function (item) {
viewModel.toggleSelect(item, true);
});
};
self.clearSelection = function () {
this.focus(null); this.focus(null);
// unselect previous elements // unselect previous elements
self.selection().forEach(function(item) { self.selection().forEach(function (item) {
item.selected(false); item.selected(false);
}); });
self.selection([]); self.selection([]);
}; };
self.focus.subscribe(function(oldValue) { self.focus.subscribe(function (oldValue) {
if (oldValue) { if (oldValue) {
oldValue.hasFocus(false); oldValue.hasFocus(false);
} }
}, this, "beforeChange"); }, this, "beforeChange");
self.afterRenderMediaFolderTemplate = function(elements, model) { self.afterRenderMediaFolderTemplate = function (elements, model) {
var childTitles = $(elements).find(".media-library-folder-title"); var childTitles = $(elements).find(".media-library-folder-title");
attachFolderTitleDropEvent(childTitles); attachFolderTitleDropEvent(childTitles);
}; };
self.focus.subscribe(function(newValue) { self.focus.subscribe(function (newValue) {
if (newValue) { if (newValue) {
newValue.hasFocus(true); newValue.hasFocus(true);
@ -257,21 +286,21 @@ $(function () {
type: "GET", type: "GET",
url: url, url: url,
cache: false cache: false
}).done(function(data) { }).done(function (data) {
newValue.summary(data); newValue.summary(data);
}); });
} }
} }
}); });
self.displayFolder = function(folderPath) { self.displayFolder = function (folderPath) {
self.results([]); self.results([]);
self.displayed(folderPath); self.displayed(folderPath);
self.loadMediaItemsUrl = function (f, skip, count, order, mediaType) { self.loadMediaItemsUrl = function (f, skip, count, order, mediaType) {
return settings.mediaItemsActionUrl + '?folderPath=' + encodeURIComponent(f) + '&skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType; return settings.mediaItemsActionUrl + '?folderPath=' + encodeURIComponent(f) + '&skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType;
}; };
self.getMediaItems(pageCount); self.getMediaItems(pageCount);
}; };
@ -280,22 +309,22 @@ $(function () {
self.displayFolder(folderPath); self.displayFolder(folderPath);
}; };
self.selectRecent = function() { self.selectRecent = function () {
History.pushState({ action: 'selectRecent' }, '', '?recent'); History.pushState({ action: 'selectRecent' }, '', '?recent');
self.loadMediaItemsUrl = function (folderPath, skip, count, order, mediaType) { self.loadMediaItemsUrl = function (folderPath, skip, count, order, mediaType) {
return settings.recentMediaItemsActionUrl + '?skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType; return settings.recentMediaItemsActionUrl + '?skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType;
}; };
self.results([]); self.results([]);
self.displayed(null); self.displayed(null);
self.getMediaItems(pageCount); self.getMediaItems(pageCount);
}; };
self.toggleSelect = function(searchResult, force) { self.toggleSelect = function (searchResult, force) {
var index = $.inArray(searchResult, self.selection()); var index = $.inArray(searchResult, self.selection());
if (index == -1 || force) { if (index == -1 || force) {
self.selection.remove(function(item) { return item.data.id == searchResult.data.id; }); self.selection.remove(function (item) { return item.data.id == searchResult.data.id; });
self.selection.push(searchResult); self.selection.push(searchResult);
searchResult.selected(true); searchResult.selected(true);
} else { } else {
@ -306,7 +335,7 @@ $(function () {
this.focus(searchResult); this.focus(searchResult);
}; };
self.select = function(searchResult) { self.select = function (searchResult) {
var index = $.inArray(searchResult, self.selection()); var index = $.inArray(searchResult, self.selection());
if (index == -1) { if (index == -1) {
self.clearSelection(); self.clearSelection();
@ -317,14 +346,14 @@ $(function () {
this.focus(searchResult); this.focus(searchResult);
}; };
self.scrolled = function(data, event) { self.scrolled = function (data, event) {
var elem = event.target; var elem = event.target;
if (elem.scrollTop > (elem.scrollHeight - elem.offsetHeight - 300)) { if (elem.scrollTop > (elem.scrollHeight - elem.offsetHeight - 300)) {
self.getMediaItems(pageCount, true); self.getMediaItems(pageCount, true);
} }
}; };
self.importMedia = function() { self.importMedia = function () {
var url = settings.importActionUrl + '?folderPath=' + encodeURIComponent(self.displayed()); var url = settings.importActionUrl + '?folderPath=' + encodeURIComponent(self.displayed());
window.location = url; window.location = url;
}; };
@ -339,7 +368,8 @@ $(function () {
viewModel.selection().forEach(function (item) { ids.push(item.data.id); }); viewModel.selection().forEach(function (item) { ids.push(item.data.id); });
var actionurl = url + '?folderPath=' + encodeURIComponent(folder) + "&replaceId=" + encodeURIComponent(ids[0]); var actionurl = url + '?folderPath=' + encodeURIComponent(folder) + "&replaceId=" + encodeURIComponent(ids[0]);
window.location = actionurl; window.location = actionurl;
} };
var selectFolderOrRecent = function () { var selectFolderOrRecent = function () {
if (self.displayed()) { if (self.displayed()) {
self.selectFolder(self.displayed()); self.selectFolder(self.displayed());
@ -368,13 +398,13 @@ $(function () {
self.isExpanded = ko.observable(false); self.isExpanded = ko.observable(false);
self.isSelected = ko.computed(function() { self.isSelected = ko.computed(function () {
return (self.mediaIndexViewModel.displayed() == self.folderPath()); return (self.mediaIndexViewModel.displayed() == self.folderPath());
}); });
self.fetchChildren = function (deepestChildPath) { self.fetchChildren = function (deepestChildPath) {
self.childFoldersFetchStatus = 1; self.childFoldersFetchStatus = 1;
var getChildFolderListUrl = function (f) { var getChildFolderListUrl = function (f) {
return settings.childFolderListingActionUrl + '?folderPath=' + encodeURIComponent(f); return settings.childFolderListingActionUrl + '?folderPath=' + encodeURIComponent(f);
}; };
@ -450,7 +480,7 @@ $(function () {
}); });
enhanceViewModel(viewModel); enhanceViewModel(viewModel);
ko.applyBindings(viewModel); ko.applyBindings(viewModel);
if (settings.hasFolderPath && settings.folderPath != settings.rootFolderPath) { if (settings.hasFolderPath && settings.folderPath != settings.rootFolderPath) {
@ -478,7 +508,7 @@ $(function () {
History.pushState({ action: 'selectRecent' }, '', '?recent'); History.pushState({ action: 'selectRecent' }, '', '?recent');
} }
window.onpopstate = function(event) { window.onpopstate = function (event) {
if (event && event.state && event.state.action == 'displayFolder') { if (event && event.state && event.state.action == 'displayFolder') {
viewModel.displayFolder(event.state.folder); viewModel.displayFolder(event.state.folder);
} }
@ -488,7 +518,7 @@ $(function () {
} }
}; };
$("#media-library-main-list").on("mousedown", "li", function(e) { $("#media-library-main-list").on("mousedown", "li", function (e) {
// only for left click // only for left click
if (e.which != 1) { if (e.which != 1) {
return; return;
@ -500,46 +530,49 @@ $(function () {
} else { } else {
viewModel.select(searchResult); viewModel.select(searchResult);
} }
}).on("contextmenu", "li", function() { }).on("contextmenu", "li", function () {
var searchResult = ko.dataFor(this); var searchResult = ko.dataFor(this);
viewModel.toggleSelect(searchResult); viewModel.toggleSelect(searchResult);
return false; return false;
}); });
var pickAndClose = function () { var pickAndClose = function () {
if (parent.$.colorbox) { if (parent.$.colorbox) {
var selectedData = []; var selectedData = [];
for (var i = 0; i < viewModel.selection().length; i++) { for (var i = 0; i < viewModel.selection().length; i++) {
var selection = viewModel.selection()[i]; var selection = viewModel.selection()[i];
selectedData.push(selection.data); selectedData.push(selection.data);
} }
parent.$.colorbox.selectedData = selectedData; parent.$.colorbox.selectedData = selectedData;
parent.$.colorbox.close(); parent.$.colorbox.close();
}; }
} };
$("#media-library-main-selection-select > .button-select").on('click', function () { $("#media-library-main-selection-select > .button-select").on('click', function () {
pickAndClose(); pickAndClose();
});
$("#select-all-button").on('click', function () {
viewModel.updateAllSelection();
}); });
$("#media-library-main-list").on('dblclick', function () { $("#media-library-main-list").on('dblclick', function () {
pickAndClose(); pickAndClose();
}); });
$("#media-library-main-selection-select > .button-cancel").on('click', function() { $("#media-library-main-selection-select > .button-cancel").on('click', function () {
if (parent.$.colorbox) { if (parent.$.colorbox) {
parent.$.colorbox.selectedData = null; parent.$.colorbox.selectedData = null;
parent.$.colorbox.close(); parent.$.colorbox.close();
} }
;
}); });
$("#media-library-main-list").on("mouseover", ".media-thumbnail", function() { $("#media-library-main-list").on("mouseover", ".media-thumbnail", function () {
if (!$(this).hasClass("ui-draggable")) { if (!$(this).hasClass("ui-draggable")) {
$(this).draggable({ $(this).draggable({
revert: 'invalid', revert: 'invalid',
//containment: 'li', //containment: 'li',
helper: function(event) { helper: function (event) {
var clone = $(event.currentTarget).clone().removeAttr('id'); var clone = $(event.currentTarget).clone().removeAttr('id');
clone.removeClass('selected'); clone.removeClass('selected');
clone.addClass('dragged-selection'); clone.addClass('dragged-selection');
@ -554,7 +587,7 @@ $(function () {
cursor: 'move', cursor: 'move',
distance: 10, distance: 10,
appendTo: 'body', appendTo: 'body',
create: function() { create: function () {
// position the handler a little left to the center to let the number of selected items to appear // position the handler a little left to the center to let the number of selected items to appear
$(this).draggable("option", "cursorAt", { left: $(this).width() / 2 - 20, top: $(this).height() / 2 }); $(this).draggable("option", "cursorAt", { left: $(this).width() / 2 - 20, top: $(this).height() / 2 });
} }
@ -562,13 +595,13 @@ $(function () {
} }
}); });
$('#delete-selection-button').click(function() { $('#delete-selection-button').click(function () {
if (!confirm(settings.deleteConfirmationMessage)) { if (!confirm(settings.deleteConfirmationMessage)) {
return false; return false;
} }
var ids = []; var ids = [];
viewModel.selection().forEach(function(item) { ids.push(item.data.id); }); viewModel.selection().forEach(function (item) { ids.push(item.data.id); });
var url = settings.deleteActionUrl; var url = settings.deleteActionUrl;
$.ajax({ $.ajax({
@ -580,9 +613,9 @@ $(function () {
mediaItemIds: ids, mediaItemIds: ids,
__RequestVerificationToken: settings.antiForgeryToken __RequestVerificationToken: settings.antiForgeryToken
} }
}).done(function(result) { }).done(function (result) {
if (result) { if (result) {
viewModel.results.remove(function(item) { viewModel.results.remove(function (item) {
return ids.indexOf(item.data.id) != -1; return ids.indexOf(item.data.id) != -1;
}); });
@ -632,4 +665,4 @@ $(function () {
}); });
})(window.mediaLibrarySettings); })(window.mediaLibrarySettings);
}) });

View File

@ -95,7 +95,8 @@ namespace Orchard.MediaLibrary.Services {
if (!String.IsNullOrEmpty(folderPath)) { if (!String.IsNullOrEmpty(folderPath)) {
if (recursive) { if (recursive) {
query = query.Join<MediaPartRecord>().Where(m => m.FolderPath.StartsWith(folderPath)); var subfolderSearch = folderPath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? folderPath : folderPath + Path.DirectorySeparatorChar;
query = query.Join<MediaPartRecord>().Where(m => (m.FolderPath == folderPath || m.FolderPath.StartsWith(subfolderSearch)));
} }
else { else {
query = query.Join<MediaPartRecord>().Where(m => m.FolderPath == folderPath); query = query.Join<MediaPartRecord>().Where(m => m.FolderPath == folderPath);

View File

@ -22,6 +22,11 @@
<a href="#" data-bind="attr: { href: '@HttpUtility.JavaScriptStringEncode(Url.Action("Create", "Folder", new { area = "Orchard.MediaLibrary"}))?folderPath=' + encodeURIComponent(displayed() ? displayed() : '') }" class="button" id="button-create-folder">@T("Create Folder")</a> <a href="#" data-bind="attr: { href: '@HttpUtility.JavaScriptStringEncode(Url.Action("Create", "Folder", new { area = "Orchard.MediaLibrary"}))?folderPath=' + encodeURIComponent(displayed() ? displayed() : '') }" class="button" id="button-create-folder">@T("Create Folder")</a>
@Display(Model.CustomActionsShapes) @Display(Model.CustomActionsShapes)
<button class="button" id="select-all-button"
data-select-all-text="@T("Select All")" data-select-none-text="@T("Select None")"
data-bind="visible: results().length > 0">
@T("Select All")
</button>
</div> </div>
<div id="media-library-main"> <div id="media-library-main">
<div id="media-library-main-navigation"> <div id="media-library-main-navigation">
@ -43,7 +48,7 @@
</div> </div>
<div class="media-library-main-list-overlay"> <div class="media-library-main-list-overlay">
<p class="title" data-bind="text: data.title, attr: { title: data.title }"></p> <p class="title" data-bind="text: data.title, attr: { title: data.title }"></p>
<p class="publication-status" data-bind="text: mediaInfos"></p> <p class="publication-status" data-bind="text: publicationStatus"></p>
</div> </div>
</li> </li>
</ul> </ul>

View File

@ -47,7 +47,7 @@
@Display(BuildDisplay(contentItem, "Thumbnail")) @Display(BuildDisplay(contentItem, "Thumbnail"))
<div class="overlay"> <div class="overlay">
<h3>@Html.ItemDisplayText(contentItem)</h3> <h3>@Html.ItemDisplayText(contentItem)</h3>
<p class="publication-status" data-bind="text: mediaInfos"> <p class="publication-status" data-bind="text: publicationStatus">
@(contentItem.IsPublished() ? "" : T("Draft").Text) @(contentItem.IsPublished() ? "" : T("Draft").Text)
@{ @{
var localizationPart = contentItem.As<LocalizationPart>(); var localizationPart = contentItem.As<LocalizationPart>();

View File

@ -44,7 +44,7 @@ namespace Orchard.Packaging.Services {
} }
public Localizer T { get; set; } public Localizer T { get; set; }
public Logging.ILogger Logger { get; set; } public Logging.ILogger Logger { get; set; }
public PackageInfo Install(string packageId, string version, string location, string applicationPath) { public PackageInfo Install(string packageId, string version, string location, string applicationPath) {
// instantiates the appropriate package repository // instantiates the appropriate package repository
@ -54,7 +54,9 @@ namespace Orchard.Packaging.Services {
var packageVersion = String.IsNullOrEmpty(version) ? null : new Version(version); var packageVersion = String.IsNullOrEmpty(version) ? null : new Version(version);
var package = packageRepository.FindPackage(packageId, packageVersion); var package = packageRepository.FindPackage(packageId, packageVersion);
if (package == null) { if (package == null) {
throw new ArgumentException(T("The specified package could not be found, id:{0} version:{1}", packageId, String.IsNullOrEmpty(version) ? T("No version").Text : version).Text); var message = T("The specified package could not be found: ID: {0}, version: {1}.",
packageId, string.IsNullOrEmpty(version) ? T("No version").Text : version);
throw new OrchardException(message);
} }
return InstallPackage(package, packageRepository, location, applicationPath); return InstallPackage(package, packageRepository, location, applicationPath);
@ -92,8 +94,8 @@ namespace Orchard.Packaging.Services {
// check the new package is compatible with current Orchard version // check the new package is compatible with current Orchard version
var descriptor = package.GetExtensionDescriptor(packageInfo.ExtensionType); var descriptor = package.GetExtensionDescriptor(packageInfo.ExtensionType);
if(descriptor != null) { if (descriptor != null) {
if(new FlatPositionComparer().Compare(descriptor.OrchardVersion, typeof(ContentItem).Assembly.GetName().Version.ToString()) >= 0) { if (new FlatPositionComparer().Compare(descriptor.OrchardVersion, typeof(ContentItem).Assembly.GetName().Version.ToString()) >= 0) {
if (previousInstalled) { if (previousInstalled) {
// restore the previous version // restore the previous version
RestoreExtensionFolder(package.ExtensionFolder(), package.ExtensionId()); RestoreExtensionFolder(package.ExtensionFolder(), package.ExtensionId());
@ -105,7 +107,7 @@ namespace Orchard.Packaging.Services {
Logger.Error(String.Format("The package is compatible with version {0} and above. Please update Orchard or install another version of this package.", descriptor.OrchardVersion)); Logger.Error(String.Format("The package is compatible with version {0} and above. Please update Orchard or install another version of this package.", descriptor.OrchardVersion));
throw new OrchardException(T("The package is compatible with version {0} and above. Please update Orchard or install another version of this package.", descriptor.OrchardVersion)); throw new OrchardException(T("The package is compatible with version {0} and above. Please update Orchard or install another version of this package.", descriptor.OrchardVersion));
} }
} }
return packageInfo; return packageInfo;
@ -134,8 +136,8 @@ namespace Orchard.Packaging.Services {
var packageManager = new NuGetPackageManager( var packageManager = new NuGetPackageManager(
packageRepository, packageRepository,
new DefaultPackagePathResolver(sourceLocation), new DefaultPackagePathResolver(sourceLocation),
new PhysicalFileSystem(installedPackagesPath) {Logger = logger} new PhysicalFileSystem(installedPackagesPath) { Logger = logger }
) {Logger = logger}; ) { Logger = logger };
packageManager.InstallPackage(package, true); packageManager.InstallPackage(package, true);
installed = true; installed = true;
@ -181,7 +183,8 @@ namespace Orchard.Packaging.Services {
if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme))) { if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme))) {
extensionFullPath = _virtualPathProvider.MapPath("~/Themes/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme).Length)); extensionFullPath = _virtualPathProvider.MapPath("~/Themes/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme).Length));
} else if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module))) { }
else if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module))) {
extensionFullPath = _virtualPathProvider.MapPath("~/Modules/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module).Length)); extensionFullPath = _virtualPathProvider.MapPath("~/Modules/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module).Length));
} }
@ -201,13 +204,13 @@ namespace Orchard.Packaging.Services {
var sourcePackageRepository = new LocalPackageRepository(installedPackagesPath); var sourcePackageRepository = new LocalPackageRepository(installedPackagesPath);
try { try {
var project = new FileBasedProjectSystem(applicationPath) {Logger = logger}; var project = new FileBasedProjectSystem(applicationPath) { Logger = logger };
var projectManager = new ProjectManager( var projectManager = new ProjectManager(
sourcePackageRepository, sourcePackageRepository,
new DefaultPackagePathResolver(installedPackagesPath), new DefaultPackagePathResolver(installedPackagesPath),
project, project,
new ExtensionReferenceRepository(project, sourcePackageRepository, _extensionManager) new ExtensionReferenceRepository(project, sourcePackageRepository, _extensionManager)
) {Logger = logger}; ) { Logger = logger };
// add the package to the project // add the package to the project
projectManager.RemovePackageReference(packageId); projectManager.RemovePackageReference(packageId);
@ -220,8 +223,8 @@ namespace Orchard.Packaging.Services {
var packageManager = new NuGetPackageManager( var packageManager = new NuGetPackageManager(
sourcePackageRepository, sourcePackageRepository,
new DefaultPackagePathResolver(applicationPath), new DefaultPackagePathResolver(applicationPath),
new PhysicalFileSystem(installedPackagesPath) {Logger = logger} new PhysicalFileSystem(installedPackagesPath) { Logger = logger }
) {Logger = logger}; ) { Logger = logger };
packageManager.UninstallPackage(packageId); packageManager.UninstallPackage(packageId);
} }
@ -314,7 +317,7 @@ namespace Orchard.Packaging.Services {
Uninstall(package.Id, _virtualPathProvider.MapPath("~\\")); Uninstall(package.Id, _virtualPathProvider.MapPath("~\\"));
_notifier.Success(T("Successfully un-installed local package {0}", package.ExtensionId())); _notifier.Success(T("Successfully un-installed local package {0}", package.ExtensionId()));
} }
catch {} catch { }
} }
} }
} }

View File

@ -1,9 +1,7 @@
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using NuGet; using NuGet;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.Environment.Features; using Orchard.Environment.Features;
using Orchard.Environment.State; using Orchard.Environment.State;

View File

@ -49,6 +49,10 @@ namespace Orchard.Projections.FilterEditors.Forms {
f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Ends), Text = T("Ends with").Text }); f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Ends), Text = T("Ends with").Text });
f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotEnds), Text = T("Does not end with").Text }); f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotEnds), Text = T("Does not end with").Text });
f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotContains), Text = T("Does not contain").Text }); f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotContains), Text = T("Does not contain").Text });
f._Operator.Add(new SelectListItem {
Value = Convert.ToString(StringOperator.ContainsAnyIfProvided),
Text = T("Contains any word (if any is provided)").Text
});
return f; return f;
}; };
@ -88,6 +92,14 @@ namespace Orchard.Projections.FilterEditors.Forms {
return y => y.Not(x => x.Like(property, Convert.ToString(value), HqlMatchMode.End)); return y => y.Not(x => x.Like(property, Convert.ToString(value), HqlMatchMode.End));
case StringOperator.NotContains: case StringOperator.NotContains:
return y => y.Not(x => x.Like(property, Convert.ToString(value), HqlMatchMode.Anywhere)); return y => y.Not(x => x.Like(property, Convert.ToString(value), HqlMatchMode.Anywhere));
case StringOperator.ContainsAnyIfProvided:
if (string.IsNullOrWhiteSpace((string)value))
return x => x.IsNotEmpty("Id"); // basically, return every possible ContentItem
var values3 = Convert.ToString(value)
.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var predicates3 = values3.Skip(1)
.Select<string, Action<IHqlExpressionFactory>>(x => y => y.Like(property, x, HqlMatchMode.Anywhere)).ToArray();
return x => x.Disjunction(y => y.Like(property, values3[0], HqlMatchMode.Anywhere), predicates3);
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
@ -118,6 +130,11 @@ namespace Orchard.Projections.FilterEditors.Forms {
return T("{0} does not end with '{1}'", fieldName, value); return T("{0} does not end with '{1}'", fieldName, value);
case StringOperator.NotContains: case StringOperator.NotContains:
return T("{0} does not contain '{1}'", fieldName, value); return T("{0} does not contain '{1}'", fieldName, value);
case StringOperator.ContainsAnyIfProvided:
return T("{0} contains any of '{1}' (or '{1}' is empty)",
fieldName,
new LocalizedString(string.Join("', '",
value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))));
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
@ -135,5 +152,6 @@ namespace Orchard.Projections.FilterEditors.Forms {
Ends, Ends,
NotEnds, NotEnds,
NotContains, NotContains,
ContainsAnyIfProvided
} }
} }

View File

@ -1,4 +1,5 @@
@using System.Globalization @using System.Globalization
@{ @{
var currentCulture = WorkContext.CurrentCulture; var currentCulture = WorkContext.CurrentCulture;
var supportedCultures = (IList<string>)Model.SupportedCultures; var supportedCultures = (IList<string>)Model.SupportedCultures;
@ -8,22 +9,25 @@
<select> <select>
@foreach (var supportedCulture in supportedCultures) { @foreach (var supportedCulture in supportedCultures) {
var cultureInfo = CultureInfo.GetCultureInfo(supportedCulture); var cultureInfo = CultureInfo.GetCultureInfo(supportedCulture);
var url = Url.Action("ChangeCulture", "AdminCultureSelector", new { area = "Orchard.Localization", culture = supportedCulture, returnUrl = Html.ViewContext.HttpContext.Request.RawUrl });
<option @if (supportedCulture.Equals(currentCulture)) { <text> selected="selected" </text> } value="@url"> if (cultureInfo is object) {
@cultureInfo.DisplayName&#x200E; var url = Url.Action("ChangeCulture", "AdminCultureSelector", new { area = "Orchard.Localization", culture = supportedCulture, returnUrl = Html.ViewContext.HttpContext.Request.RawUrl });
</option> var selected = supportedCulture.Equals(currentCulture) ? "selected" : "";
<option @selected value="@url">@cultureInfo.DisplayName</option>
}
} }
</select> </select>
</div> </div>
@using (Script.Foot()) { @using (Script.Foot()) {
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
(function ($) { (function ($) {
$("#culture-selection").change(function (e) { $("#culture-selection").change(function (e) {
window.location = $("#culture-selection > select > option:selected")[0].value; window.location = $("#culture-selection > select > option:selected")[0].value;
}); });
})(jQuery); })(jQuery);
//]]> //]]>
</script> </script>
} }

View File

@ -24,4 +24,12 @@ namespace Orchard.ContentManagement {
public readonly IList<GroupInfo> DisplayGroupInfo = new List<GroupInfo>(); public readonly IList<GroupInfo> DisplayGroupInfo = new List<GroupInfo>();
public readonly IList<GroupInfo> EditorGroupInfo = new List<GroupInfo>(); public readonly IList<GroupInfo> EditorGroupInfo = new List<GroupInfo>();
} }
public enum ContentItemRoute {
Admin,
Create,
Editor,
Remove,
Display
}
} }

View File

@ -5,8 +5,10 @@ using System.Web.Routing;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.DisplayManagement; using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors; using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath; using Orchard.FileSystems.VirtualPath;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Mvc.Routes;
using Orchard.UI.Zones; using Orchard.UI.Zones;
namespace Orchard.ContentManagement { namespace Orchard.ContentManagement {
@ -18,6 +20,8 @@ namespace Orchard.ContentManagement {
private readonly RequestContext _requestContext; private readonly RequestContext _requestContext;
private readonly IVirtualPathProvider _virtualPathProvider; private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IWorkContextAccessor _workContextAccessor; private readonly IWorkContextAccessor _workContextAccessor;
private readonly ShellSettings _shellSettings;
private readonly UrlPrefix _urlPrefix;
public DefaultContentDisplay( public DefaultContentDisplay(
Lazy<IEnumerable<IContentHandler>> handlers, Lazy<IEnumerable<IContentHandler>> handlers,
@ -25,15 +29,19 @@ namespace Orchard.ContentManagement {
Lazy<IShapeTableLocator> shapeTableLocator, Lazy<IShapeTableLocator> shapeTableLocator,
RequestContext requestContext, RequestContext requestContext,
IVirtualPathProvider virtualPathProvider, IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor) { IWorkContextAccessor workContextAccessor,
ShellSettings shellSettings) {
_handlers = handlers; _handlers = handlers;
_shapeFactory = shapeFactory; _shapeFactory = shapeFactory;
_shapeTableLocator = shapeTableLocator; _shapeTableLocator = shapeTableLocator;
_requestContext = requestContext; _requestContext = requestContext;
_virtualPathProvider = virtualPathProvider; _virtualPathProvider = virtualPathProvider;
_workContextAccessor = workContextAccessor; _workContextAccessor = workContextAccessor;
_shellSettings = shellSettings;
if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix))
_urlPrefix = new UrlPrefix(_shellSettings.RequestUrlPrefix);
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
} }
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
@ -158,7 +166,12 @@ namespace Orchard.ContentManagement {
/// Gets the current app-relative path, i.e. ~/my-blog/foo. /// Gets the current app-relative path, i.e. ~/my-blog/foo.
/// </summary> /// </summary>
private string GetPath() { private string GetPath() {
return VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path)); var appRelativePath = _virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path);
// If the tenant has a prefix, we strip the tenant prefix away.
if (_urlPrefix != null)
appRelativePath = _urlPrefix.RemoveLeadingSegments(appRelativePath);
return VirtualPathUtility.AppendTrailingSlash(appRelativePath);
} }
} }
} }

View File

@ -1,29 +0,0 @@
using System.Web.Routing;
using System.Web.Mvc;
namespace Orchard.Mvc.Extensions {
public static class RouteExtension{
public static string GetAreaName(this RouteBase route){
var routeWithArea = route as IRouteWithArea;
if (routeWithArea != null) {
return routeWithArea.Area;
}
var castRoute = route as Route;
if (castRoute != null && castRoute.DataTokens != null) {
return castRoute.DataTokens["area"] as string;
}
return null;
}
public static string GetAreaName(this RouteData routeData){
object area;
if (routeData.DataTokens.TryGetValue("area", out area)) {
return area as string;
}
return GetAreaName(routeData.Route);
}
}
}

View File

@ -0,0 +1,25 @@
using System.Web.Mvc;
using System.Web.Routing;
namespace Orchard.Mvc.Extensions {
public static class RouteExtensions {
public static string GetAreaName(this RouteBase route) {
if (route is IRouteWithArea routeWithArea) {
return routeWithArea.Area;
}
if (route is Route castRoute && castRoute.DataTokens != null) {
return castRoute.DataTokens["area"] as string;
}
return null;
}
public static string GetAreaName(this RouteData routeData) =>
routeData.DataTokens.TryGetValue("area", out object area) ?
area as string : GetAreaName(routeData.Route);
public static string ToRouteString(this RouteValueDictionary route) =>
string.Join("/", route["Area"], route["Controller"], route["Action"]);
}
}

View File

@ -401,7 +401,7 @@
<Compile Include="Mvc\DataAnnotations\LocalizedRangeAttribute.cs" /> <Compile Include="Mvc\DataAnnotations\LocalizedRangeAttribute.cs" />
<Compile Include="Mvc\DataAnnotations\LocalizedModelValidatorProvider.cs" /> <Compile Include="Mvc\DataAnnotations\LocalizedModelValidatorProvider.cs" />
<Compile Include="Mvc\DataAnnotations\LocalizedRequiredAttribute.cs" /> <Compile Include="Mvc\DataAnnotations\LocalizedRequiredAttribute.cs" />
<Compile Include="Mvc\Extensions\RouteExtension.cs" /> <Compile Include="Mvc\Extensions\RouteExtensions.cs" />
<Compile Include="Mvc\Extensions\HttpContextBaseExtensions.cs" /> <Compile Include="Mvc\Extensions\HttpContextBaseExtensions.cs" />
<Compile Include="Mvc\FormValueRequiredAttribute.cs" /> <Compile Include="Mvc\FormValueRequiredAttribute.cs" />
<Compile Include="Mvc\HttpContextAccessor.cs" /> <Compile Include="Mvc\HttpContextAccessor.cs" />

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
namespace Orchard.Security.Permissions { namespace Orchard.Security.Permissions {
public class Permission { public class Permission {
@ -7,10 +8,12 @@ namespace Orchard.Security.Permissions {
public string Category { get; set; } public string Category { get; set; }
public IEnumerable<Permission> ImpliedBy { get; set; } public IEnumerable<Permission> ImpliedBy { get; set; }
public bool RequiresOwnership { get; set; }
public static Permission Named(string name) { public static Permission Named(string name) {
return new Permission { Name = name }; return new Permission { Name = name };
} }
[Obsolete("This property is not used anywhere, so it shouldn't be referenced.")]
public bool RequiresOwnership { get; set; }
} }
} }