mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-08-01 17:51:18 +08:00
Fixing taxonomy navigation
This commit is contained in:
parent
2f45a02a1f
commit
a45d4b29d9
@ -149,7 +149,7 @@ namespace Orchard.Taxonomies.Controllers {
|
|||||||
var taxonomy = _taxonomyService.GetTaxonomy(taxonomyId);
|
var taxonomy = _taxonomyService.GetTaxonomy(taxonomyId);
|
||||||
var parentTerm = _taxonomyService.GetTerm(parentTermId);
|
var parentTerm = _taxonomyService.GetTerm(parentTermId);
|
||||||
var term = _taxonomyService.NewTerm(taxonomy);
|
var term = _taxonomyService.NewTerm(taxonomy);
|
||||||
|
|
||||||
// assign a container to show the full route while editing
|
// assign a container to show the full route while editing
|
||||||
term.Container = parentTerm == null ? taxonomy : (IContent)parentTerm;
|
term.Container = parentTerm == null ? taxonomy : (IContent)parentTerm;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.Drivers;
|
using Orchard.ContentManagement.Drivers;
|
||||||
|
using Orchard.Localization;
|
||||||
using Orchard.Taxonomies.Models;
|
using Orchard.Taxonomies.Models;
|
||||||
using Orchard.Taxonomies.Services;
|
using Orchard.Taxonomies.Services;
|
||||||
using Orchard.Taxonomies.ViewModels;
|
using Orchard.Taxonomies.ViewModels;
|
||||||
@ -15,6 +16,8 @@ namespace Orchard.Taxonomies.Drivers {
|
|||||||
_taxonomyService = taxonomyService;
|
_taxonomyService = taxonomyService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
protected override string Prefix { get { return "TaxonomyNavigationPart"; } }
|
protected override string Prefix { get { return "TaxonomyNavigationPart"; } }
|
||||||
|
|
||||||
protected override DriverResult Editor(TaxonomyNavigationPart part, dynamic shapeHelper) {
|
protected override DriverResult Editor(TaxonomyNavigationPart part, dynamic shapeHelper) {
|
||||||
@ -30,17 +33,25 @@ namespace Orchard.Taxonomies.Drivers {
|
|||||||
DisplayContentCount = part.DisplayContentCount,
|
DisplayContentCount = part.DisplayContentCount,
|
||||||
DisplayTopMenuItem = part.DisplayRootTerm,
|
DisplayTopMenuItem = part.DisplayRootTerm,
|
||||||
HideEmptyTerms = part.HideEmptyTerms,
|
HideEmptyTerms = part.HideEmptyTerms,
|
||||||
|
LevelsToDisplay = part.LevelsToDisplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (updater != null) {
|
if (updater != null) {
|
||||||
if (updater.TryUpdateModel(model, Prefix, null, null)) {
|
if (updater.TryUpdateModel(model, Prefix, null, null)) {
|
||||||
// taxonomy to render
|
|
||||||
part.TaxonomyId = model.SelectedTaxonomyId;
|
if (model.LevelsToDisplay < 0) {
|
||||||
// root term (can be null)
|
updater.AddModelError("LevelsToDisplay", T("The levels to display must be a positive number"));
|
||||||
part.TermId = model.SelectedTermId;
|
}
|
||||||
part.DisplayContentCount = model.DisplayContentCount;
|
else {
|
||||||
part.DisplayRootTerm = model.DisplayTopMenuItem;
|
// taxonomy to render
|
||||||
part.HideEmptyTerms = model.HideEmptyTerms;
|
part.TaxonomyId = model.SelectedTaxonomyId;
|
||||||
|
// root term (can be null)
|
||||||
|
part.TermId = model.SelectedTermId;
|
||||||
|
part.DisplayContentCount = model.DisplayContentCount;
|
||||||
|
part.DisplayRootTerm = model.DisplayTopMenuItem;
|
||||||
|
part.HideEmptyTerms = model.HideEmptyTerms;
|
||||||
|
part.LevelsToDisplay = model.LevelsToDisplay;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Orchard.Taxonomies.Fields;
|
using Orchard.Taxonomies.Fields;
|
||||||
using Orchard.Taxonomies.Models;
|
using Orchard.Taxonomies.Models;
|
||||||
@ -59,10 +60,19 @@ namespace Orchard.Taxonomies.Handlers {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve the number of associated content items, for the whole hierarchy
|
||||||
private static void RecalculateCount(ITaxonomyService taxonomyService, TermsPart part) {
|
private static void RecalculateCount(ITaxonomyService taxonomyService, TermsPart part) {
|
||||||
foreach (var term in part.Terms) {
|
foreach (var term in part.Terms) {
|
||||||
var termPart = taxonomyService.GetTerm(term.TermRecord.Id);
|
var termPart = taxonomyService.GetTerm(term.TermRecord.Id);
|
||||||
term.TermRecord.Count = (int)taxonomyService.GetContentItemsCount(termPart);
|
while (termPart != null) {
|
||||||
|
termPart.Count = (int)taxonomyService.GetContentItemsCount(termPart);
|
||||||
|
|
||||||
|
// compute count for the hierarchy too
|
||||||
|
if (termPart.Container != null) {
|
||||||
|
var parentTerm = termPart.Container.As<TermPart>();
|
||||||
|
termPart = parentTerm;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
|
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
|
||||||
@ -32,6 +33,14 @@ namespace Orchard.Taxonomies.Models {
|
|||||||
set { this.As<InfosetPart>().Set("TaxonomyNavigationPart", "DisplayRootTerm", null, Convert.ToString(value, CultureInfo.InvariantCulture)); }
|
set { this.As<InfosetPart>().Set("TaxonomyNavigationPart", "DisplayRootTerm", null, Convert.ToString(value, CultureInfo.InvariantCulture)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of levels to render. If <value>0</value> all levels are rendered.
|
||||||
|
/// </summary>
|
||||||
|
public int LevelsToDisplay {
|
||||||
|
get { return Convert.ToInt32(this.As<InfosetPart>().Get("TaxonomyNavigationPart", "LevelsToDisplay"), CultureInfo.InvariantCulture); }
|
||||||
|
set { this.As<InfosetPart>().Set("TaxonomyNavigationPart", "LevelsToDisplay", Convert.ToString(value, CultureInfo.InvariantCulture)); }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to display the number of content items
|
/// Whether to display the number of content items
|
||||||
/// associated with this term, in the generated menu item text
|
/// associated with this term, in the generated menu item text
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
|
using Orchard.Taxonomies.Helpers;
|
||||||
using Orchard.Taxonomies.Models;
|
using Orchard.Taxonomies.Models;
|
||||||
using Orchard.Taxonomies.Services;
|
using Orchard.Taxonomies.Services;
|
||||||
using Orchard.UI.Navigation;
|
using Orchard.UI.Navigation;
|
||||||
using Orchard.Taxonomies.Helpers;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Orchard.Taxonomies.Navigation {
|
namespace Orchard.Taxonomies.Navigation {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dynamically injects query results as menu items on NavigationQueryMenuItem elements
|
/// Dynamically injects taxonomy items as menu items on TaxonomyNavigationMenuItem elements
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TaxonomyNavigationProvider : INavigationFilter {
|
public class TaxonomyNavigationProvider : INavigationFilter {
|
||||||
private readonly IContentManager _contentManager;
|
private readonly IContentManager _contentManager;
|
||||||
@ -28,60 +28,66 @@ namespace Orchard.Taxonomies.Navigation {
|
|||||||
|
|
||||||
foreach (var item in items) {
|
foreach (var item in items) {
|
||||||
if (item.Content != null && item.Content.ContentItem.ContentType == "TaxonomyNavigationMenuItem") {
|
if (item.Content != null && item.Content.ContentItem.ContentType == "TaxonomyNavigationMenuItem") {
|
||||||
// expand query
|
|
||||||
|
|
||||||
var taxonomyNavigationPart = item.Content.As<TaxonomyNavigationPart>();
|
var taxonomyNavigationPart = item.Content.As<TaxonomyNavigationPart>();
|
||||||
|
|
||||||
var rootTerm = _taxonomyService.GetTerm(taxonomyNavigationPart.TermId);
|
var rootTerm = _taxonomyService.GetTerm(taxonomyNavigationPart.TermId);
|
||||||
|
|
||||||
List<int> positionList = new List<int>();
|
TermPart[] allTerms;
|
||||||
|
|
||||||
var allTerms = rootTerm != null
|
if (rootTerm != null) {
|
||||||
? _taxonomyService.GetChildren(rootTerm).ToArray()
|
// if DisplayRootTerm is specified add it to the menu items to render
|
||||||
: _taxonomyService.GetTerms(taxonomyNavigationPart.TaxonomyId).ToArray();
|
allTerms = _taxonomyService.GetChildren(rootTerm, taxonomyNavigationPart.DisplayRootTerm).ToArray();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
allTerms = _taxonomyService.GetTerms(taxonomyNavigationPart.TaxonomyId).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
var rootlevel = rootTerm == null ? 0 : rootTerm.GetLevels();
|
var rootLevel = rootTerm != null
|
||||||
|
? rootTerm.GetLevels()
|
||||||
|
: 0;
|
||||||
|
|
||||||
positionList.Add(0);
|
|
||||||
|
|
||||||
var menuPosition = item.Position;
|
var menuPosition = item.Position;
|
||||||
int parentLevel = rootlevel;
|
var rootPath = rootTerm == null || taxonomyNavigationPart.DisplayRootTerm ? "" : rootTerm.FullPath;
|
||||||
|
|
||||||
|
var startLevel = rootLevel + 1;
|
||||||
|
if (rootTerm == null || taxonomyNavigationPart.DisplayRootTerm) {
|
||||||
|
startLevel = rootLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
var endLevel = Int32.MaxValue;
|
||||||
|
if (taxonomyNavigationPart.LevelsToDisplay > 0) {
|
||||||
|
endLevel = startLevel + taxonomyNavigationPart.LevelsToDisplay - 1;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var contentItem in allTerms) {
|
foreach (var contentItem in allTerms) {
|
||||||
if (contentItem != null) {
|
if (contentItem != null) {
|
||||||
var part = contentItem;
|
var part = contentItem;
|
||||||
|
var level = part.GetLevels();
|
||||||
|
|
||||||
if (taxonomyNavigationPart.HideEmptyTerms == true && part.Count == 0) {
|
// filter levels ?
|
||||||
|
if (level < startLevel || level > endLevel) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
string termPosition = "";
|
|
||||||
if (part.GetLevels() - rootlevel > parentLevel) {
|
|
||||||
positionList.Add(0);
|
|
||||||
parentLevel = positionList.Count - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ((part.GetLevels() - rootlevel) == parentLevel) {
|
|
||||||
positionList[parentLevel]++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
positionList.RemoveRange(1, positionList.Count - 1);
|
|
||||||
parentLevel = positionList.Count - 1;
|
|
||||||
positionList[parentLevel]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
termPosition = positionList.First().ToString();
|
// ignore menu item if there are no content items associated to the term
|
||||||
foreach (var position in positionList.Skip(1)) {
|
if (taxonomyNavigationPart.HideEmptyTerms && part.Count == 0) {
|
||||||
termPosition = termPosition + "." + position.ToString();
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var menuText = _contentManager.GetItemMetadata(part).DisplayText;
|
var menuText = _contentManager.GetItemMetadata(part).DisplayText;
|
||||||
var routes = _contentManager.GetItemMetadata(part).DisplayRouteValues;
|
var routes = _contentManager.GetItemMetadata(part).DisplayRouteValues;
|
||||||
|
|
||||||
if (taxonomyNavigationPart.DisplayContentCount) {
|
if (taxonomyNavigationPart.DisplayContentCount) {
|
||||||
menuText = String.Format(menuText + " ({0})", part.Count.ToString());
|
menuText += " (" + part.Count + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create
|
||||||
|
var positions = contentItem.FullPath.Substring(rootPath.Length)
|
||||||
|
.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(p => Array.FindIndex(allTerms, t => t.Id == Int32.Parse(p)))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
var inserted = new MenuItem {
|
var inserted = new MenuItem {
|
||||||
Text = new LocalizedString(menuText),
|
Text = new LocalizedString(menuText),
|
||||||
IdHint = item.IdHint,
|
IdHint = item.IdHint,
|
||||||
@ -92,7 +98,7 @@ namespace Orchard.Taxonomies.Navigation {
|
|||||||
RouteValues = routes,
|
RouteValues = routes,
|
||||||
LocalNav = item.LocalNav,
|
LocalNav = item.LocalNav,
|
||||||
Items = new MenuItem[0],
|
Items = new MenuItem[0],
|
||||||
Position = menuPosition + ":" + termPosition,
|
Position = menuPosition + ":" + String.Join(".", positions.Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray()),
|
||||||
Permissions = item.Permissions,
|
Permissions = item.Permissions,
|
||||||
Content = part
|
Content = part
|
||||||
};
|
};
|
||||||
|
@ -28,6 +28,7 @@ namespace Orchard.Taxonomies.Services {
|
|||||||
void UpdateTerms(ContentItem contentItem, IEnumerable<TermPart> terms, string field);
|
void UpdateTerms(ContentItem contentItem, IEnumerable<TermPart> terms, string field);
|
||||||
IEnumerable<TermPart> GetParents(TermPart term);
|
IEnumerable<TermPart> GetParents(TermPart term);
|
||||||
IEnumerable<TermPart> GetChildren(TermPart term);
|
IEnumerable<TermPart> GetChildren(TermPart term);
|
||||||
|
IEnumerable<TermPart> GetChildren(TermPart term, bool includeParent);
|
||||||
IEnumerable<IContent> GetContentItems(TermPart term, int skip = 0, int count = 0, string fieldName = null);
|
IEnumerable<IContent> GetContentItems(TermPart term, int skip = 0, int count = 0, string fieldName = null);
|
||||||
long GetContentItemsCount(TermPart term, string fieldName = null);
|
long GetContentItemsCount(TermPart term, string fieldName = null);
|
||||||
IContentQuery<TermsPart, TermsPartRecord> GetContentItemsQuery(TermPart term, string fieldName = null);
|
IContentQuery<TermsPart, TermsPartRecord> GetContentItemsQuery(TermPart term, string fieldName = null);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Orchard.Taxonomies.Fields;
|
|
||||||
using Orchard.Taxonomies.Models;
|
using Orchard.Taxonomies.Models;
|
||||||
using Orchard.Autoroute.Models;
|
using Orchard.Autoroute.Models;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
@ -267,12 +266,20 @@ namespace Orchard.Taxonomies.Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TermPart> GetChildren(TermPart term) {
|
public IEnumerable<TermPart> GetChildren(TermPart term) {
|
||||||
|
return GetChildren(term, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TermPart> GetChildren(TermPart term, bool includeParent) {
|
||||||
var rootPath = term.FullPath + "/";
|
var rootPath = term.FullPath + "/";
|
||||||
|
|
||||||
var result = _contentManager.Query<TermPart, TermPartRecord>()
|
var result = _contentManager.Query<TermPart, TermPartRecord>()
|
||||||
.WithQueryHints(new QueryHints().ExpandRecords<AutoroutePartRecord, TitlePartRecord, CommonPartRecord>())
|
.WithQueryHints(new QueryHints().ExpandRecords<AutoroutePartRecord, TitlePartRecord, CommonPartRecord>())
|
||||||
.List()
|
.Where(x => x.Path.StartsWith(rootPath))
|
||||||
.Where(x => x.Path.StartsWith(rootPath));
|
.List();
|
||||||
|
|
||||||
|
if (includeParent) {
|
||||||
|
result = result.Concat(new [] {term});
|
||||||
|
}
|
||||||
|
|
||||||
return TermPart.Sort(result);
|
return TermPart.Sort(result);
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,6 @@ namespace Orchard.Taxonomies.ViewModels {
|
|||||||
public bool DisplayTopMenuItem { get; set; }
|
public bool DisplayTopMenuItem { get; set; }
|
||||||
public bool DisplayContentCount { get; set; }
|
public bool DisplayContentCount { get; set; }
|
||||||
public bool HideEmptyTerms { get; set; }
|
public bool HideEmptyTerms { get; set; }
|
||||||
|
public int LevelsToDisplay { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,13 @@
|
|||||||
<span class="hint">@T("When checked, the selected term to display will be rendered as a root element in the menu.")</span>
|
<span class="hint">@T("When checked, the selected term to display will be rendered as a root element in the menu.")</span>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<label for="@Html.FieldIdFor( m => m.LevelsToDisplay)">@T("Levels to display")</label>
|
||||||
|
@Html.TextBoxFor(m => m.LevelsToDisplay, new { @class = "text small" } )
|
||||||
|
@Html.ValidationMessage("LevelsToDisplay", "*")
|
||||||
|
<span class="hint">@T("The number of levels to display in the hierarchy. 0 to display all levels.")</span>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@Html.CheckBoxFor(m => m.HideEmptyTerms)
|
@Html.CheckBoxFor(m => m.HideEmptyTerms)
|
||||||
<label for="@Html.FieldIdFor(m => m.HideEmptyTerms)" class="forcheckbox">@T("Hide empty entries")</label>
|
<label for="@Html.FieldIdFor(m => m.HideEmptyTerms)" class="forcheckbox">@T("Hide empty entries")</label>
|
||||||
|
Loading…
Reference in New Issue
Block a user