/src/Orchard/UI/Navigation/NavigationHelper.cs

http://associativy.codeplex.com · C# · 219 lines · 128 code · 27 blank · 64 comment · 42 complexity · 57d9040688ba6d35e659be2dc5f08e44 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Routing;
  6. namespace Orchard.UI.Navigation {
  7. public static class NavigationHelper {
  8. /// <summary>
  9. /// Populates the menu shapes.
  10. /// </summary>
  11. /// <param name="shapeFactory">The shape factory.</param>
  12. /// <param name="parentShape">The menu parent shape.</param>
  13. /// <param name="menu">The menu shape.</param>
  14. /// <param name="menuItems">The current level to populate.</param>
  15. public static void PopulateMenu(dynamic shapeFactory, dynamic parentShape, dynamic menu, IEnumerable<MenuItem> menuItems) {
  16. foreach (MenuItem menuItem in menuItems) {
  17. dynamic menuItemShape = BuildMenuItemShape(shapeFactory, parentShape, menu, menuItem);
  18. if (menuItem.Items != null && menuItem.Items.Any()) {
  19. PopulateMenu(shapeFactory, menuItemShape, menu, menuItem.Items);
  20. }
  21. parentShape.Add(menuItemShape, menuItem.Position);
  22. }
  23. }
  24. /// <summary>
  25. /// Populates the local menu starting from the first non local task parent.
  26. /// </summary>
  27. /// <param name="shapeFactory">The shape factory.</param>
  28. /// <param name="parentShape">The menu parent shape.</param>
  29. /// <param name="menu">The menu shape.</param>
  30. /// <param name="selectedPath">The selection path.</param>
  31. public static void PopulateLocalMenu(dynamic shapeFactory, dynamic parentShape, dynamic menu, Stack<MenuItem> selectedPath) {
  32. MenuItem parentMenuItem = FindParentLocalTask(selectedPath);
  33. // find childs tabs and expand them
  34. if (parentMenuItem != null && parentMenuItem.Items != null && parentMenuItem.Items.Any()) {
  35. PopulateLocalMenu(shapeFactory, parentShape, menu, parentMenuItem.Items);
  36. }
  37. }
  38. /// <summary>
  39. /// Populates the local menu shapes.
  40. /// </summary>
  41. /// <param name="shapeFactory">The shape factory.</param>
  42. /// <param name="parentShape">The menu parent shape.</param>
  43. /// <param name="menu">The menu shape.</param>
  44. /// <param name="menuItems">The current level to populate.</param>
  45. public static void PopulateLocalMenu(dynamic shapeFactory, dynamic parentShape, dynamic menu, IEnumerable<MenuItem> menuItems) {
  46. foreach (MenuItem menuItem in menuItems) {
  47. dynamic menuItemShape = BuildLocalMenuItemShape(shapeFactory, parentShape, menu, menuItem);
  48. if (menuItem.Items != null && menuItem.Items.Any()) {
  49. PopulateLocalMenu(shapeFactory, menuItemShape, menu, menuItem.Items);
  50. }
  51. parentShape.Add(menuItemShape, menuItem.Position);
  52. }
  53. }
  54. /// <summary>
  55. /// Identifies the currently selected path, starting from the selected node.
  56. /// </summary>
  57. /// <param name="menuItems">All the menuitems in the navigation menu.</param>
  58. /// <param name="currentRequest">The currently executed request if any</param>
  59. /// <param name="currentRouteData">The current route data.</param>
  60. /// <returns>A stack with the selection path being the last node the currently selected one.</returns>
  61. public static Stack<MenuItem> SetSelectedPath(IEnumerable<MenuItem> menuItems, HttpRequestBase currentRequest, RouteData currentRouteData) {
  62. return SetSelectedPath(menuItems, currentRequest, currentRouteData.Values);
  63. }
  64. /// <summary>
  65. /// Identifies the currently selected path, starting from the selected node.
  66. /// </summary>
  67. /// <param name="menuItems">All the menuitems in the navigation menu.</param>
  68. /// <param name="currentRequest">The currently executed request if any</param>
  69. /// <param name="currentRouteData">The current route data.</param>
  70. /// <returns>A stack with the selection path being the last node the currently selected one.</returns>
  71. public static Stack<MenuItem> SetSelectedPath(IEnumerable<MenuItem> menuItems, HttpRequestBase currentRequest, RouteValueDictionary currentRouteData) {
  72. if (menuItems == null)
  73. return null;
  74. foreach (MenuItem menuItem in menuItems) {
  75. Stack<MenuItem> selectedPath = SetSelectedPath(menuItem.Items, currentRequest, currentRouteData);
  76. if (selectedPath != null) {
  77. menuItem.Selected = true;
  78. selectedPath.Push(menuItem);
  79. return selectedPath;
  80. }
  81. bool match = false;
  82. // if the menu item doesn't have route values, compare urls
  83. if (currentRequest != null && menuItem.RouteValues == null) {
  84. string requestUrl = currentRequest.Path.Replace(currentRequest.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
  85. string modelUrl = menuItem.Href.Replace(currentRequest.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
  86. if (requestUrl == modelUrl || (!string.IsNullOrEmpty(modelUrl) && requestUrl.StartsWith(modelUrl + "/"))) {
  87. match = true;
  88. }
  89. }
  90. else {
  91. if (RouteMatches(menuItem.RouteValues, currentRouteData)) {
  92. match = true;
  93. }
  94. }
  95. if (match) {
  96. menuItem.Selected = true;
  97. selectedPath = new Stack<MenuItem>();
  98. selectedPath.Push(menuItem);
  99. return selectedPath;
  100. }
  101. }
  102. return null;
  103. }
  104. /// <summary>
  105. /// Find the first level in the selection path, starting from the bottom, that is not a local task.
  106. /// </summary>
  107. /// <param name="selectedPath">The selection path stack. The bottom node is the currently selected one.</param>
  108. /// <returns>The first node, starting from the bottom, that is not a local task. Otherwise, null.</returns>
  109. public static MenuItem FindParentLocalTask(Stack<MenuItem> selectedPath) {
  110. if (selectedPath != null) {
  111. MenuItem parentMenuItem = selectedPath.Pop();
  112. if (parentMenuItem != null) {
  113. while (selectedPath.Count > 0) {
  114. MenuItem currentMenuItem = selectedPath.Pop();
  115. if (currentMenuItem.LocalNav) {
  116. return parentMenuItem;
  117. }
  118. parentMenuItem = currentMenuItem;
  119. }
  120. }
  121. }
  122. return null;
  123. }
  124. /// <summary>
  125. /// Determines if a menu item corresponds to a given route.
  126. /// </summary>
  127. /// <param name="itemValues">The menu item.</param>
  128. /// <param name="requestValues">The route data.</param>
  129. /// <returns>True if the menu item's action corresponds to the route data; false otherwise.</returns>
  130. public static bool RouteMatches(RouteValueDictionary itemValues, RouteValueDictionary requestValues) {
  131. if (itemValues == null && requestValues == null) {
  132. return true;
  133. }
  134. if (itemValues == null || requestValues == null) {
  135. return false;
  136. }
  137. if (itemValues.Keys.Any(key => requestValues.ContainsKey(key) == false)) {
  138. return false;
  139. }
  140. return itemValues.Keys.All(key => string.Equals(Convert.ToString(itemValues[key]), Convert.ToString(requestValues[key]), StringComparison.OrdinalIgnoreCase));
  141. }
  142. /// <summary>
  143. /// Builds a menu item shape.
  144. /// </summary>
  145. /// <param name="shapeFactory">The shape factory.</param>
  146. /// <param name="parentShape">The parent shape.</param>
  147. /// <param name="menu">The menu shape.</param>
  148. /// <param name="menuItem">The menu item to build the shape for.</param>
  149. /// <returns>The menu item shape.</returns>
  150. public static dynamic BuildMenuItemShape(dynamic shapeFactory, dynamic parentShape, dynamic menu, MenuItem menuItem) {
  151. var menuItemShape = shapeFactory.MenuItem()
  152. .Text(menuItem.Text)
  153. .IdHint(menuItem.IdHint)
  154. .Href(menuItem.Href)
  155. .LinkToFirstChild(menuItem.LinkToFirstChild)
  156. .LocalNav(menuItem.LocalNav)
  157. .Selected(menuItem.Selected)
  158. .RouteValues(menuItem.RouteValues)
  159. .Item(menuItem)
  160. .Menu(menu)
  161. .Parent(parentShape)
  162. .Content(menuItem.Content);
  163. foreach (var className in menuItem.Classes)
  164. menuItemShape.Classes.Add(className);
  165. return menuItemShape;
  166. }
  167. /// <summary>
  168. /// Builds a local menu item shape.
  169. /// </summary>
  170. /// <param name="shapeFactory">The shape factory.</param>
  171. /// <param name="parentShape">The parent shape.</param>
  172. /// <param name="menu">The menu shape.</param>
  173. /// <param name="menuItem">The menu item to build the shape for.</param>
  174. /// <returns>The menu item shape.</returns>
  175. public static dynamic BuildLocalMenuItemShape(dynamic shapeFactory, dynamic parentShape, dynamic menu, MenuItem menuItem) {
  176. var menuItemShape = shapeFactory.LocalMenuItem()
  177. .Text(menuItem.Text)
  178. .IdHint(menuItem.IdHint)
  179. .Href(menuItem.Href)
  180. .LinkToFirstChild(menuItem.LinkToFirstChild)
  181. .LocalNav(menuItem.LocalNav)
  182. .Selected(menuItem.Selected)
  183. .RouteValues(menuItem.RouteValues)
  184. .Item(menuItem)
  185. .Menu(menu)
  186. .Parent(parentShape);
  187. foreach (var className in menuItem.Classes)
  188. menuItemShape.Classes.Add(className);
  189. return menuItemShape;
  190. }
  191. }
  192. }