Changing MenuItem .Text to LocalizedString

Updating comparer to avoid collapsing url and routevalue items together
Flattened the navigation admin controller to avoid using MenuItem class in editor model
HtmlEncode the text of the menu item to be displayed
Updated TheMenu templates to use .text and .hinttext properties of LocalizedString

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2011-02-26 18:29:00 -08:00
parent 10bba3b135
commit 4a4ac2ef07
16 changed files with 80 additions and 72 deletions

View File

@@ -63,8 +63,8 @@ namespace Orchard.Tests.UI.Navigation {
}
private static Mock<INavigationManager> GetNavigationManager() {
var mainMenu = new[] { new MenuItem { Text = "The Main Menu" } };
var adminMenu = new[] { new MenuItem { Text = "The Admin Menu" } };
var mainMenu = new[] { new MenuItem { Text = new LocalizedString("The Main Menu") } };
var adminMenu = new[] { new MenuItem { Text = new LocalizedString("The Admin Menu") } };
var navigationManager = new Mock<INavigationManager>();
navigationManager.Setup(x => x.BuildMenu("main")).Returns(mainMenu);
navigationManager.Setup(x => x.BuildMenu("admin")).Returns(adminMenu);

View File

@@ -1,5 +1,6 @@
using System.Web.Routing;
using NUnit.Framework;
using Orchard.Localization;
using Orchard.UI.Navigation;
namespace Orchard.Tests.UI.Navigation {
@@ -7,50 +8,50 @@ namespace Orchard.Tests.UI.Navigation {
public class MenuItemComparerTests {
[Test]
public void TextShouldCauseDifferenceAndNullRouteValuesAreEqual() {
var item1 = new MenuItem { TextHint = "hello" };
var item2 = new MenuItem { TextHint = "hello" };
var item3 = new MenuItem { TextHint = "hello3" };
var item1 = new MenuItem { Text = new LocalizedString("hello") };
var item2 = new MenuItem { Text = new LocalizedString("hello") };
var item3 = new MenuItem { Text = new LocalizedString("hello3") };
AssertSameSameDifferent(item1, item2, item3);
}
[Test]
public void NullRouteValuesShouldEqualEmptyRouteValues() {
var item1 = new MenuItem { TextHint = "hello" };
var item2 = new MenuItem { TextHint = "hello" };
var item3 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary() };
var item4 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary() };
var item1 = new MenuItem { Text = new LocalizedString("hello") };
var item2 = new MenuItem { Text = new LocalizedString("hello") };
var item3 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary() };
var item4 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary() };
AssertSameSameSame(item1, item2, item3);
AssertSameSameSame(item3, item4, item1);
}
[Test]
public void AdditionalPropertiesShouldMismatch() {
var item1 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item2 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item3 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = 1, two = 2 }) };
var item1 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item2 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item3 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = 1, two = 2 }) };
AssertSameSameDifferent(item1, item2, item3);
}
[Test]
public void ValueTypeShouldMismatch() {
var item1 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item2 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item3 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = "1" }) };
var item1 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item2 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = 1 }) };
var item3 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = "1" }) };
AssertSameSameDifferent(item1, item2, item3);
}
[Test]
public void ValuesShouldMismatch() {
var item1 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }) };
var item2 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }) };
var item3 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = "1", two = "3" }) };
var item1 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }) };
var item2 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }) };
var item3 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = "1", two = "3" }) };
AssertSameSameDifferent(item1, item2, item3);
}
[Test]
public void PositionAndChildrenDontMatter() {
var item1 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }) };
var item2 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }), Position = "4.0" };
var item3 = new MenuItem { TextHint = "hello", RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }), Items = new[] { new MenuItem() } };
var item1 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }) };
var item2 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }), Position = "4.0" };
var item3 = new MenuItem { Text = new LocalizedString("hello"), RouteValues = new RouteValueDictionary(new { one = "1", two = "2" }), Items = new[] { new MenuItem() } };
AssertSameSameSame(item1, item2, item3);
}

View File

@@ -56,19 +56,19 @@ namespace Orchard.Tests.UI.Navigation {
var item2 = menuItems.Skip(1).First();
var item3 = menuItems.Skip(2).First();
Assert.That(item1.TextHint, Is.EqualTo("Foo"));
Assert.That(item1.Text, Is.EqualTo("Foo"));
Assert.That(item1.Position, Is.EqualTo("1.0"));
Assert.That(item2.TextHint, Is.EqualTo("Bar"));
Assert.That(item2.Text, Is.EqualTo("Bar"));
Assert.That(item2.Position, Is.EqualTo("2.0"));
Assert.That(item3.TextHint, Is.EqualTo("Frap"));
Assert.That(item3.Text, Is.EqualTo("Frap"));
Assert.That(item3.Position, Is.EqualTo("3.0"));
Assert.That(item2.Items.Count(), Is.EqualTo(2));
var subitem1 = item2.Items.First();
var subitem2 = item2.Items.Last();
Assert.That(subitem1.TextHint, Is.EqualTo("Quad"));
Assert.That(subitem1.Text, Is.EqualTo("Quad"));
Assert.That(subitem1.Position, Is.EqualTo("1.a"));
Assert.That(subitem2.TextHint, Is.EqualTo("Frap"));
Assert.That(subitem2.Text, Is.EqualTo("Frap"));
Assert.That(subitem2.Position, Is.EqualTo("1.b"));
}

View File

@@ -42,7 +42,7 @@ namespace Orchard.Core.Navigation.Controllers {
model = new NavigationManagementViewModel();
if (model.MenuItemEntries == null || model.MenuItemEntries.Count() < 1)
model.MenuItemEntries = _menuService.Get().Select(CreateMenuItemEntries).OrderBy(menuPartEntry => menuPartEntry.MenuItem.Position, new FlatPositionComparer()).ToList();
model.MenuItemEntries = _menuService.Get().Select(CreateMenuItemEntries).OrderBy(menuPartEntry => menuPartEntry.Position, new FlatPositionComparer()).ToList();
// need action name as this action is referenced from another action
return View("Index", model);
@@ -58,10 +58,10 @@ namespace Orchard.Core.Navigation.Controllers {
foreach (var menuItemEntry in menuItemEntries) {
MenuPart menuPart = _menuService.Get(menuItemEntry.MenuItemId);
menuPart.MenuText = menuItemEntry.MenuItem.Text;
menuPart.MenuPosition = menuItemEntry.MenuItem.Position;
menuPart.MenuText = menuItemEntry.Text;
menuPart.MenuPosition = menuItemEntry.Position;
if (menuPart.Is<MenuItemPart>())
menuPart.As<MenuItemPart>().Url = menuItemEntry.MenuItem.Url;
menuPart.As<MenuItemPart>().Url = menuItemEntry.Url;
}
}
@@ -70,15 +70,13 @@ namespace Orchard.Core.Navigation.Controllers {
private MenuItemEntry CreateMenuItemEntries(MenuPart menuPart) {
return new MenuItemEntry {
MenuItem = new MenuItem {
MenuItemId = menuPart.Id,
IsMenuItem = menuPart.Is<MenuItemPart>(),
Text = menuPart.MenuText,
Position = menuPart.MenuPosition,
Url = menuPart.Is<MenuItemPart>()
? menuPart.As<MenuItemPart>().Url
: _navigationManager.GetUrl(null, _services.ContentManager.GetItemMetadata(menuPart).DisplayRouteValues)
},
MenuItemId = menuPart.Id,
IsMenuItem = menuPart.Is<MenuItemPart>()
: _navigationManager.GetUrl(null, _services.ContentManager.GetItemMetadata(menuPart).DisplayRouteValues),
};
}
@@ -96,7 +94,7 @@ namespace Orchard.Core.Navigation.Controllers {
if (!ModelState.IsValid) {
_services.TransactionManager.Cancel();
return Index(new NavigationManagementViewModel {NewMenuItem = model});
return Index(new NavigationManagementViewModel { NewMenuItem = model });
}
if (string.IsNullOrEmpty(menuPart.MenuPosition))

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations;
using System.Web;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Core.Navigation.Models;
using Orchard.Localization;
@@ -23,11 +24,11 @@ namespace Orchard.Core.Navigation.Services {
if (part.Is<MenuItemPart>())
builder.Add(
menu => menu.Add(new LocalizedString(part.MenuText), part.MenuPosition, nib => nib.Url(part.As<MenuItemPart>().Url)));
menu => menu.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, nib => nib.Url(part.As<MenuItemPart>().Url)));
else
builder.Add(
menu =>
menu.Add(new LocalizedString(part.MenuText), part.MenuPosition,
menu.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition,
nib =>
nib.Action(_contentManager.GetItemMetadata(part.ContentItem).DisplayRouteValues)));
}

View File

@@ -2,8 +2,11 @@
namespace Orchard.Core.Navigation.ViewModels {
public class MenuItemEntry {
public MenuItem MenuItem { get; set; }
public int MenuItemId { get; set; }
public bool IsMenuItem { get; set; }
public string Text { get; set; }
public string Url { get; set; }
public string Position { get; set; }
}
}

View File

@@ -26,9 +26,9 @@
foreach (var menuPartEntry in Model.MenuItemEntries) {
var i = menuPartEntryIndex;
<tr>
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItem.Text)" value="@menuPartEntry.MenuItem.Text" /></td>
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItem.Position)" value="@menuPartEntry.MenuItem.Position" /></td>
<td>@if (!menuPartEntry.IsMenuItem) {<input type="text" class="text-box disabled" disabled="disabled" value="@menuPartEntry.MenuItem.Url" /> } else {<input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItem.Url)" value="@menuPartEntry.MenuItem.Url" />}</td>
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Text)" value="@menuPartEntry.Text" /></td>
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Position)" value="@menuPartEntry.Position" /></td>
<td>@if (!menuPartEntry.IsMenuItem) {<input type="text" class="text-box disabled" disabled="disabled" value="@menuPartEntry.Url" /> } else {<input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Url)" value="@menuPartEntry.Url" />}</td>
<td><input type="hidden" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItemId)" value="@menuPartEntry.MenuItemId" /><a href="@Html.AntiForgeryTokenGetUrl(Url.Action("Delete", new {id = menuPartEntry.MenuItemId}))" class="remove">@T("Remove")</a></td>
</tr>
++menuPartEntryIndex;

View File

@@ -9,7 +9,7 @@
@tag.StartElement
@foreach(var firstLevelMenuItem in Model) {
if (firstLevelMenuItem.LocalNav) {
string sectionHeaderText = firstLevelMenuItem.Text;
string sectionHeaderText = firstLevelMenuItem.Text.Text;
var sectionHeaderMarkup = firstLevelMenuItem.RouteValues != null || HasText(firstLevelMenuItem.Url)
? Html.Link(sectionHeaderText, (string)firstLevelMenuItem.Href)

View File

@@ -16,8 +16,8 @@
@foreach(var firstLevelMenuItem in Model) {
IEnumerable<dynamic> secondLevelMenuItems = firstLevelMenuItem;
string sectionHeaderText = firstLevelMenuItem.Text;
string sectionHeaderTextHint = firstLevelMenuItem.TextHint;
string sectionHeaderText = firstLevelMenuItem.Text.Text;
string sectionHeaderTextHint = firstLevelMenuItem.Text.TextHint;
var firstOfTheSecond = secondLevelMenuItems.FirstOrDefault();
var itemClassName = HasText(sectionHeaderTextHint)
@@ -64,7 +64,7 @@
if (secondLevelMenuItems.Where(menuItem => !menuItem.LocalNav).Count() > 1 || !firstLevelMenuItem.LinkToFirstChild) {
<ul class="menuItems">
@foreach (var secondLevelMenuItem in secondLevelMenuItems.Where(menuItem => !menuItem.LocalNav)) {
string secondLevelTextHint = secondLevelMenuItem.TextHint;
string secondLevelTextHint = secondLevelMenuItem.Text.TextHint;
var secondLevelItemClassName = HasText(secondLevelTextHint)
? "subnavicon-" + secondLevelTextHint.HtmlClassify()
: "subnavicon";

View File

@@ -8,8 +8,9 @@ namespace Orchard.Localization {
private readonly string _textHint;
private readonly object[] _args;
public LocalizedString(string localized) {
_localized = localized;
public LocalizedString(string languageNeutral) {
_localized = languageNeutral;
_textHint = languageNeutral;
}
public LocalizedString(string localized, string scope, string textHint, object[] args) {

View File

@@ -194,7 +194,6 @@ namespace Orchard.UI.Navigation {
protected dynamic BuildMenuItemShape(dynamic shapeFactory, dynamic parentShape, dynamic menu, MenuItem menuItem) {
return shapeFactory.MenuItem()
.Text(menuItem.Text)
.TextHint(menuItem.TextHint)
.IdHint(menuItem.IdHint)
.Href(menuItem.Href)
.LinkToFirstChild(menuItem.LinkToFirstChild)
@@ -217,7 +216,6 @@ namespace Orchard.UI.Navigation {
protected dynamic BuildLocalMenuItemShape(dynamic shapeFactory, dynamic parentShape, dynamic menu, MenuItem menuItem) {
return shapeFactory.LocalMenuItem()
.Text(menuItem.Text)
.TextHint(menuItem.TextHint)
.IdHint(menuItem.IdHint)
.Href(menuItem.Href)
.LinkToFirstChild(menuItem.LinkToFirstChild)

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;
using Orchard.Localization;
using Orchard.Security.Permissions;
namespace Orchard.UI.Navigation {
@@ -10,8 +11,7 @@ namespace Orchard.UI.Navigation {
LinkToFirstChild = true;
}
public string Text { get; set; }
public string TextHint { get; set; }
public LocalizedString Text { get; set; }
public string IdHint { get; set; }
public string Url { get; set; }
public string Href { get; set; }

View File

@@ -4,9 +4,12 @@ using System.Linq;
namespace Orchard.UI.Navigation {
public class MenuItemComparer : IEqualityComparer<MenuItem> {
public bool Equals(MenuItem x, MenuItem y) {
if (!string.Equals(x.TextHint, y.TextHint)) {
if (x.Text != null && y.Text != null) {
if (!string.Equals(x.Text.TextHint, y.Text.TextHint)) {
return false;
}
}
if (!string.IsNullOrWhiteSpace(x.Url) && !string.IsNullOrWhiteSpace(y.Url)) {
if (!string.Equals(x.Url, y.Url)) {
return false;
@@ -26,13 +29,20 @@ namespace Orchard.UI.Navigation {
}
}
if (!string.IsNullOrWhiteSpace(x.Url) && y.RouteValues != null) {
return false;
}
if (!string.IsNullOrWhiteSpace(y.Url) && x.RouteValues != null) {
return false;
}
return true;
}
public int GetHashCode(MenuItem obj) {
var hash = 0;
if (obj.TextHint != null) {
hash ^= obj.TextHint.GetHashCode();
if (obj.Text != null && obj.Text.TextHint != null) {
hash ^= obj.Text.TextHint.GetHashCode();
}
return hash;
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.Localization;
namespace Orchard.UI.Navigation {

View File

@@ -13,10 +13,7 @@ namespace Orchard.UI.Navigation {
}
public NavigationItemBuilder Caption(LocalizedString caption) {
if (caption != null) {
_item.Text = caption.Text;
_item.TextHint = caption.TextHint;
}
_item.Text = caption;
return this;
}
@@ -41,7 +38,7 @@ namespace Orchard.UI.Navigation {
}
public NavigationItemBuilder Permission(Permission permission) {
_item.Permissions = _item.Permissions.Concat(new[]{permission});
_item.Permissions = _item.Permissions.Concat(new[] { permission });
return this;
}

View File

@@ -74,7 +74,6 @@ namespace Orchard.UI.Navigation {
RouteValues = item.RouteValues,
LocalNav = item.LocalNav,
Text = item.Text,
TextHint = item.TextHint,
IdHint = item.IdHint,
Url = item.Url,
LinkToFirstChild = item.LinkToFirstChild,
@@ -116,7 +115,7 @@ namespace Orchard.UI.Navigation {
// order position groups by position
.OrderBy(positionGroup => positionGroup.Key, orderer)
// ordered by item text in the postion group
.SelectMany(positionGroup => positionGroup.OrderBy(item => item.Text));
.SelectMany(positionGroup => positionGroup.OrderBy(item => item.Text == null ? "" : item.Text.TextHint));
}
static MenuItem Join(IEnumerable<MenuItem> items) {
@@ -125,7 +124,6 @@ namespace Orchard.UI.Navigation {
var joined = new MenuItem {
Text = items.First().Text,
TextHint = items.First().TextHint,
IdHint = items.Select(x => x.IdHint).FirstOrDefault(x => !string.IsNullOrWhiteSpace(x)),
Url = items.Select(x => x.Url).FirstOrDefault(x => !string.IsNullOrWhiteSpace(x)),
Href = items.Select(x => x.Href).FirstOrDefault(x => !string.IsNullOrWhiteSpace(x)),