Merge pull request #6314 from OrchardCMS/issue/3537-alias-breadcrumb-linnk

Implementing Alias Breadcrumb Link to be able to add dynamically gene…
This commit is contained in:
Zoltán Lehóczky
2016-01-29 17:58:06 +01:00
10 changed files with 184 additions and 2 deletions

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Navigation.Models;
namespace Orchard.Core.Navigation.Drivers {
public class BreadcrumbMenuItemPartDriver : ContentPartDriver<BreadcrumbMenuItemPart> {
}
}

View File

@@ -11,6 +11,7 @@ using Orchard.Core.Title.Models;
using Orchard.Localization;
using Orchard.UI.Navigation;
using Orchard.Utility.Extensions;
using Orchard.ContentManagement.Utilities;
namespace Orchard.Core.Navigation.Drivers {
public class MenuWidgetPartDriver : ContentPartDriver<MenuWidgetPart> {
@@ -50,6 +51,11 @@ namespace Orchard.Core.Navigation.Drivers {
var menuName = menu.As<TitlePart>().Title.HtmlClassify();
var currentCulture = _workContextAccessor.GetContext().CurrentCulture;
var menuItems = _navigationManager.BuildMenu(menu);
if (!part.Breadcrumb) {
menuItems = menuItems.Where(x => !x.Content.Has<BreadcrumbMenuItemPart>());
}
var localized = new List<MenuItem>();
foreach(var menuItem in menuItems) {
// if there is no associated content, it as culture neutral

View File

@@ -0,0 +1,6 @@
using Orchard.ContentManagement;
namespace Orchard.Core.Navigation.Models {
public class BreadcrumbMenuItemPart : ContentPart {
}
}

View File

@@ -76,7 +76,7 @@ namespace Orchard.Core.Navigation.Services {
private IEnumerable<MenuItem> Filter(IEnumerable<MenuItem> menuItems) {
IEnumerable<MenuItem> result = menuItems;
foreach(var filter in _navigationFilters) {
foreach (var filter in _navigationFilters) {
result = filter.Filter(result);
}

View File

@@ -172,6 +172,7 @@
<Compile Include="Dashboard\Services\CompilationErrorBanner.cs" />
<Compile Include="Navigation\Commands\MenuCommands.cs" />
<Compile Include="Navigation\Drivers\AdminMenuPartDriver.cs" />
<Compile Include="Navigation\Drivers\BreadcrumbMenuItemPartDriver.cs" />
<Compile Include="Navigation\Drivers\MenuItemPartDriver.cs" />
<Compile Include="Navigation\Drivers\MenuWidgetPartDriver.cs" />
<Compile Include="Navigation\Drivers\ShapeMenuItemPartDriver.cs" />
@@ -182,6 +183,7 @@
<Compile Include="Navigation\Handlers\MenuWidgetPartHandler.cs" />
<Compile Include="Navigation\Models\AdminMenuPart.cs" />
<Compile Include="Navigation\Models\AdminMenuPartRecord.cs" />
<Compile Include="Navigation\Models\BreadcrumbMenuItemPart.cs" />
<Compile Include="Navigation\Models\MenuWidgetPart.cs" />
<Compile Include="Navigation\Models\ShapeMenuItemPart.cs" />
<Compile Include="Navigation\Security\AuthorizationEventHandler.cs" />

View File

@@ -0,0 +1,24 @@
using Orchard.Data.Migration;
using Orchard.ContentManagement.MetaData;
using Orchard.Environment.Extensions;
using Orchard.Core.Navigation.Models;
namespace Orchard.Alias {
[OrchardFeature("Orchard.Alias.BreadcrumbLink")]
public class AliasBreadcrumbMigration : DataMigrationImpl {
public int Create() {
ContentDefinitionManager.AlterTypeDefinition("AliasBreadcrumbMenuItem",
cfg => cfg
.WithPart("BreadcrumbMenuItemPart")
.WithPart("MenuPart")
.WithPart("CommonPart")
.WithIdentity()
.DisplayedAs("Alias Breadcrumb Link")
.WithSetting("Description", "A menu item that can be used to generate breadcrumb links, using Alias data, to content items without explicitly adding links to those content items in the menu.")
.WithSetting("Stereotype", "MenuItem")
);
return 1;
}
}
}

View File

@@ -27,6 +27,5 @@ namespace Orchard.Alias {
);
return 2;
}
}
}

View File

@@ -18,3 +18,8 @@ Features:
Description: Synchronizes aliases when created from different servers.
Dependencies: Orchard.Alias
Category: Content
Orchard.Alias.BreadcrumbLink:
Name: Alias Breadcrumb Link
Description: Provides Alias Breadcrumb Link menu item type that can be used to generate breadcrumb links, using Alias data, to content items without explicitly adding links to those content items in the menu.
Dependencies: Orchard.Alias
Category: Navigation

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.Mvc;
using Orchard.UI.Navigation;
namespace Orchard.Alias.Navigation {
[OrchardFeature("Orchard.Alias.BreadcrumbLink")]
public class NavigationAliasProvider : INavigationFilter {
private readonly IAliasService _aliasService;
private readonly IContentManager _contentManager;
private readonly IHttpContextAccessor _hca;
public NavigationAliasProvider(
IAliasService aliasService,
IContentManager contentManager,
IHttpContextAccessor hca) {
_aliasService = aliasService;
_contentManager = contentManager;
_hca = hca;
}
public IEnumerable<MenuItem> Filter(IEnumerable<MenuItem> items) {
foreach (var item in items) {
if (item.Content != null && item.Content.ContentItem.ContentType == "AliasBreadcrumbMenuItem") {
var request = _hca.Current().Request;
var path = request.Path;
var appPath = request.ApplicationPath ?? "/";
var requestUrl = (path.StartsWith(appPath) ? path.Substring(appPath.Length) : path).TrimStart('/');
var endsWithSlash = requestUrl.EndsWith("/");
var menuPosition = item.Position;
var urlLevel = endsWithSlash ? requestUrl.Count(l => l == '/') - 1 : requestUrl.Count(l => l == '/');
var menuLevel = menuPosition.Count(l => l == '.');
// Checking menu item if it's the leaf element or it's an intermediate element
// or it's an unneccessary element according to the url.
RouteValueDictionary contentRoute;
if (menuLevel == urlLevel) {
contentRoute = request.RequestContext.RouteData.Values;
}
else {
// If menuLevel doesn't equal with urlLevel it can mean that this menu item is
// an intermediate element (the difference is a positive value) or this menu
// item is lower in the navigation hierarchy according to the url (negative
// value). If the value is negative, removing the menu item, if the value
// is positive finding its place in the hierarchy.
var levelDifference = urlLevel - menuLevel;
if (levelDifference > 0) {
if (endsWithSlash) {
levelDifference += levelDifference;
}
for (int i = 0; i < levelDifference; i++) {
requestUrl = requestUrl.Remove(requestUrl.LastIndexOf('/'));
path = path.Remove(path.LastIndexOf('/'));
}
contentRoute = _aliasService.Get(requestUrl);
if (contentRoute == null) {
// After the exact number of segments is cut out from the url and the
// currentRoute is still null, trying another check with the added slash,
// because we don't know if the alias was created with a slash at the end or not.
contentRoute = _aliasService.Get(requestUrl.Insert(requestUrl.Length, "/"));
path = path.Insert(path.Length, "/");
if (contentRoute == null) {
contentRoute = new RouteValueDictionary();
}
}
}
else {
contentRoute = new RouteValueDictionary();
}
}
object id;
contentRoute.TryGetValue("Id", out id);
int contentId;
int.TryParse(id as string, out contentId);
if (contentId == 0) {
// If failed to get the Id's value from currentRoute, transform the alias to the virtual path
// and try to get the content item's id from there. E.g. "Blogs/Blog/Item?blogId=12" where
// the last digits represents the content item's id. If there is a match in the path we get
// the digits after the equality sign.
// There is an another type of the routes: like "Contents/Item/Display/13", but when the
// content item's route is in this form we already have the id from contentRoute.TryGetValue("Id", out id).
var virtualPath = _aliasService.LookupVirtualPaths(contentRoute, _hca.Current()).FirstOrDefault();
int.TryParse(virtualPath != null ? virtualPath.VirtualPath.Substring(virtualPath.VirtualPath.LastIndexOf('=') + 1) : "0", out contentId);
}
if (contentId != 0) {
var currentContentItem = _contentManager.Get(contentId);
if (currentContentItem != null) {
var menuText = _contentManager.GetItemMetadata(currentContentItem).DisplayText;
var routes = _contentManager.GetItemMetadata(currentContentItem).DisplayRouteValues;
var inserted = new MenuItem {
Text = new LocalizedString(menuText),
IdHint = item.IdHint,
Classes = item.Classes,
Url = path,
Href = item.Href,
LinkToFirstChild = false,
RouteValues = routes,
LocalNav = item.LocalNav,
Items = Enumerable.Empty<MenuItem>(),
Position = menuPosition,
Permissions = item.Permissions,
Content = item.Content
};
yield return inserted;
}
}
}
else {
yield return item;
}
}
}
}
}

View File

@@ -101,10 +101,12 @@
<Content Include="Views\Admin\Edit.cshtml" />
<Content Include="Views\Admin\IndexUnmanaged.cshtml" />
<Content Include="Web.config" />
<Compile Include="AliasBreadcrumbLinkMigrations.cs" />
<Compile Include="Implementation\Updater\AliasHolderUpdater.cs" />
<Compile Include="Implementation\Updater\AliasUpdateCursor.cs" />
<Compile Include="Implementation\Updater\AliasUpdaterBackgroundTask.cs" />
<Compile Include="Implementation\Updater\IAliasUpdateCursor.cs" />
<Compile Include="Navigation\NavigationAliasProvider.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Content Include="Module.txt" />
</ItemGroup>