Skip to content

Commit 21fe5b4

Browse files
committed
Add overloads for link buttons
1 parent ca4ee39 commit 21fe5b4

9 files changed

Lines changed: 295 additions & 37 deletions

File tree

src/ServiceStack.Common/ViewUtils.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,83 @@ public static void NavLink(StringBuilder sb, NavItem navItem, NavOptions options
412412
sb.Append("</lI>");
413413
}
414414

415+
public static NavOptions NavBar(this NavOptions options)
416+
{
417+
if (options == null)
418+
options = new NavOptions();
419+
if (options.NavClass == NavOptions.DefaultNavClass)
420+
options.NavClass = NavOptions.DefaultNavBarClass;
421+
return options;
422+
}
423+
424+
public static NavOptions NavLinkButtons(this NavOptions options)
425+
{
426+
if (options == null)
427+
options = new NavOptions();
428+
if (options.NavClass == NavOptions.DefaultNavClass)
429+
options.NavClass = NavOptions.DefaultNavLinkButtonsClass;
430+
if (options.NavItemClass == NavOptions.DefaultNavItemClass)
431+
options.NavItemClass = NavOptions.DefaultNavLinkButtonsNavItemClass;
432+
return options;
433+
}
434+
435+
public static string NavLinkButtons(List<NavItem> navItems, NavOptions options)
436+
{
437+
if (navItems.IsEmpty())
438+
return string.Empty;
439+
440+
var sb = StringBuilderCache.Allocate();
441+
sb.Append("<div class=\"")
442+
.Append(options.NavClass)
443+
.AppendLine("\">");
444+
445+
foreach (var navItem in navItems)
446+
{
447+
NavLinkButton(sb, navItem, options);
448+
}
449+
450+
sb.AppendLine("</div>");
451+
return sb.ToString();
452+
}
453+
454+
public static string NavLinkButton(NavItem navItem, NavOptions options)
455+
{
456+
var sb = StringBuilderCache.Allocate();
457+
NavLinkButton(sb, navItem, options);
458+
return StringBuilderCache.ReturnAndFree(sb);
459+
}
460+
461+
public static void NavLinkButton(StringBuilder sb, NavItem navItem, NavOptions options)
462+
{
463+
if (!navItem.ShowNav(options.Attributes))
464+
return;
465+
466+
var activeCls = navItem.Href != null && (navItem.Exact == true || options.ActivePath.Length <= 1
467+
? options.ActivePath?.TrimEnd('/').EqualsIgnoreCase(navItem.Href?.TrimEnd('/')) == true
468+
: options.ActivePath?.TrimEnd('/').StartsWithIgnoreCase(navItem.Href?.TrimEnd('/'))) == true
469+
? " active"
470+
: "";
471+
472+
sb.Append("<a href=\"")
473+
.Append(options.HrefPrefix?.TrimEnd('/'))
474+
.Append(navItem.Href)
475+
.Append("\"");
476+
477+
sb.Append(" class=\"")
478+
.Append(navItem.Class).Append(navItem.Class != null ? " " : "")
479+
.Append(options.NavItemClass).Append(activeCls)
480+
.Append("\"");
481+
482+
if (navItem.Id != null)
483+
sb.Append(" id=\"").Append(navItem.Id).Append("\"");
484+
485+
sb.Append(">")
486+
.Append(navItem.IconHtml)
487+
.Append(navItem.Label)
488+
.AppendLine("</a>");
489+
}
490+
491+
415492
[MethodImpl(MethodImplOptions.AggressiveInlining)]
416493
public static bool IsNull(object test) => test == null || test == JsNull.Value;
417494

src/ServiceStack.Mvc/RazorFormat.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -808,16 +808,21 @@ public static HtmlString HtmlDump(this IHtmlHelper html, object target, HtmlDump
808808
public static HtmlString Nav(this IHtmlHelper html) => html.NavBar(ViewUtils.NavItems, null);
809809
public static HtmlString Nav(this IHtmlHelper html, List<NavItem> navItems) => html.NavBar(navItems, null);
810810
public static HtmlString Nav(this IHtmlHelper html, List<NavItem> navItems, NavOptions options) =>
811-
ViewUtils.Nav(navItems, options.DefaultActivePath(html.GetRequest().PathInfo)).ToHtmlString();
811+
ViewUtils.Nav(navItems, options.WithDefaults(html.GetRequest())).ToHtmlString();
812812

813813
public static HtmlString NavBar(this IHtmlHelper html) => html.NavBar(ViewUtils.NavItems, null);
814814
public static HtmlString NavBar(this IHtmlHelper html, List<NavItem> navItems) => html.NavBar(navItems, null);
815815
public static HtmlString NavBar(this IHtmlHelper html, List<NavItem> navItems, NavOptions options) =>
816-
ViewUtils.Nav(navItems, options.NavBar().DefaultActivePath(html.GetRequest().PathInfo)).ToHtmlString();
816+
ViewUtils.Nav(navItems, options.NavBar().WithDefaults(html.GetRequest())).ToHtmlString();
817817

818818
public static HtmlString NavLink(this IHtmlHelper html, NavItem navItem) => html.NavLink(navItem, null);
819819
public static HtmlString NavLink(this IHtmlHelper html, NavItem navItem, NavOptions options) =>
820-
ViewUtils.NavLink(navItem, options.DefaultActivePath(html.GetRequest().PathInfo)).ToHtmlString();
820+
ViewUtils.NavLink(navItem, options.WithDefaults(html.GetRequest())).ToHtmlString();
821+
822+
public static HtmlString NavLinkButtons(this IHtmlHelper html) => html.NavLinkButtons(ViewUtils.NavItems, null);
823+
public static HtmlString NavLinkButtons(this IHtmlHelper html, List<NavItem> navItems) => html.NavLinkButtons(navItems, null);
824+
public static HtmlString NavLinkButtons(this IHtmlHelper html, List<NavItem> navItems, NavOptions options) =>
825+
ViewUtils.NavLinkButtons(navItems, options.NavLinkButtons().WithDefaults(html.GetRequest())).ToHtmlString();
821826
}
822827

823828
public abstract class ViewPage : ViewPage<object>

src/ServiceStack.Razor/Html/HtmlExtensions.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,20 @@ public static HtmlString FormControl(this HtmlHelper html, Dictionary<string, ob
130130
public static HtmlString Nav(this HtmlHelper html) => html.NavBar(ViewUtils.NavItems, null);
131131
public static HtmlString Nav(this HtmlHelper html, List<NavItem> navItems) => html.NavBar(navItems, null);
132132
public static HtmlString Nav(this HtmlHelper html, List<NavItem> navItems, NavOptions options) =>
133-
ViewUtils.Nav(navItems, options.DefaultActivePath(html.GetRequest().PathInfo)).ToHtmlString();
133+
ViewUtils.Nav(navItems, options.WithDefaults(html.GetRequest())).ToHtmlString();
134134

135135
public static HtmlString NavBar(this HtmlHelper html) => html.NavBar(ViewUtils.NavItems, null);
136136
public static HtmlString NavBar(this HtmlHelper html, List<NavItem> navItems) => html.NavBar(navItems, null);
137137
public static HtmlString NavBar(this HtmlHelper html, List<NavItem> navItems, NavOptions options) =>
138-
ViewUtils.Nav(navItems, options.NavBar().DefaultActivePath(html.GetRequest().PathInfo)).ToHtmlString();
138+
ViewUtils.Nav(navItems, options.NavBar().WithDefaults(html.GetRequest())).ToHtmlString();
139139

140140
public static HtmlString NavLink(this HtmlHelper html, NavItem navItem) => html.NavLink(navItem, null);
141141
public static HtmlString NavLink(this HtmlHelper html, NavItem navItem, NavOptions options) =>
142-
ViewUtils.NavLink(navItem, options.DefaultActivePath(html.GetRequest().PathInfo)).ToHtmlString();
143-
142+
ViewUtils.NavLink(navItem, options.WithDefaults(html.GetRequest())).ToHtmlString();
143+
144+
public static HtmlString NavLinkButtons(this HtmlHelper html) => html.NavLinkButtons(ViewUtils.NavItems, null);
145+
public static HtmlString NavLinkButtons(this HtmlHelper html, List<NavItem> navItems) => html.NavLinkButtons(navItems, null);
146+
public static HtmlString NavLinkButtons(this HtmlHelper html, List<NavItem> navItems, NavOptions options) =>
147+
ViewUtils.NavLinkButtons(navItems, options.NavLinkButtons().WithDefaults(html.GetRequest())).ToHtmlString();
144148
}
145149
}

src/ServiceStack/BootstrapScripts.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Linq;
23
using ServiceStack.Script;
34

45
namespace ServiceStack
@@ -56,8 +57,12 @@ NavOptions ToNavOptions(ScriptScopeContext scope, Dictionary<string, object> opt
5657
var navOptions = new NavOptions();
5758
if (options != null)
5859
{
60+
if (options.TryGetValue("attributes", out var oAttributes))
61+
navOptions.Attributes = ViewUtils.ToStrings(nameof(ToNavOptions), oAttributes).ToHashSet();
5962
if (options.TryGetValue("active", out var oActive))
6063
navOptions.ActivePath = (string)oActive;
64+
if (options.TryGetValue("prefix", out var oPrefix))
65+
navOptions.HrefPrefix = (string)oPrefix;
6166
if (options.TryGetValue("navClass", out var oNavClass))
6267
navOptions.NavClass = (string) oNavClass;
6368
if (options.TryGetValue("navLinkClass", out var oNavLinkClass))
@@ -74,6 +79,8 @@ NavOptions ToNavOptions(ScriptScopeContext scope, Dictionary<string, object> opt
7479

7580
if (navOptions.ActivePath == null)
7681
navOptions.ActivePath = scope.GetValue("PathInfo")?.ToString();
82+
if (navOptions.Attributes == null)
83+
navOptions.Attributes = Context.GetServiceStackFilters().req(scope).GetUserAttributes();
7784

7885
return navOptions;
7986
}
@@ -91,5 +98,10 @@ public IRawString navbar(ScriptScopeContext scope, List<NavItem> navItems, Dicti
9198
public IRawString navLink(ScriptScopeContext scope, NavItem navItem) => navLink(scope, navItem, null);
9299
public IRawString navLink(ScriptScopeContext scope, NavItem navItem, Dictionary<string, object> options) =>
93100
ViewUtils.NavLink(navItem, ToNavOptions(scope, options)).ToRawString();
101+
102+
public IRawString navLinkButtons(ScriptScopeContext scope) => navLinkButtons(scope, ViewUtils.NavItems);
103+
public IRawString navLinkButtons(ScriptScopeContext scope, List<NavItem> navItems) => navLinkButtons(scope, navItems, null);
104+
public IRawString navLinkButtons(ScriptScopeContext scope, List<NavItem> navItems, Dictionary<string, object> options) =>
105+
ViewUtils.NavLinkButtons(navItems, ToNavOptions(scope, options).NavLinkButtons()).ToRawString();
94106
}
95107
}

tests/CheckMvcIdentityCore/appsettings.Development.json

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,35 @@
88
}
99
},
1010
"NavItems": [
11-
{ "path":"/", "label": "Home", "exact":true },
12-
{ "path":"/about", "label": "About" },
13-
{ "path":"/about/services", "label": "Services" },
14-
{ "path":"/contact", "label": "Contact",
11+
{ "href":"/", "label": "Home", "exact":true },
12+
{ "href":"/about", "label": "About" },
13+
{ "href":"/about/services", "label": "Services" },
14+
{ "href":"/contact", "label": "Contact",
1515
"children": [
16-
{ "path": "/contact/me", "label":"Me" },
17-
{ "path": "/contact/email", "label":"Email" },
16+
{ "href": "/contact/me", "label":"Me" },
17+
{ "href": "/contact/email", "label":"Email" },
1818
{ "label":"-" },
19-
{ "path": "/contact/phone", "label":"Phone" }
19+
{ "href": "/contact/phone", "label":"Phone" }
2020
]
21-
}
21+
},
22+
{ "href":"/validation/server/login", "label": "Sign In", "hide": "auth" },
23+
{ "href":"/validation/server/register", "label": "Sign Up", "hide": "auth" },
24+
{ "href":"/account", "label": "My Account", "show": "auth" },
25+
{ "href":"/admin", "label": "Admin", "show": "role:Admin" }
2226
],
2327
"NavItemsMap": {
2428
"aside": [
25-
{ "path":"/aside", "label":"Aside" }
29+
{ "href":"/aside", "label":"Aside" }
2630
],
2731
"footer": [
28-
{ "path":"/terms", "label":"Terms" },
29-
{ "path":"/privacy", "label":"Privacy" },
30-
{ "path":"/contacts", "label": "Contacts",
32+
{ "href":"/terms", "label":"Terms" },
33+
{ "href":"/privacy", "label":"Privacy" },
34+
{ "href":"/contacts", "label": "Contacts",
3135
"children": [
32-
{ "path": "/contact/me", "label":"Me" },
33-
{ "path": "/contact/email", "label":"Email" },
36+
{ "href": "/contact/me", "label":"Me" },
37+
{ "href": "/contact/email", "label":"Email" },
3438
{ "label":"-" },
35-
{ "path": "/contact/phone", "label":"Phone" }
39+
{ "href": "/contact/phone", "label":"Phone" }
3640
]
3741
}
3842
]

tests/CheckWebCore/appsettings.json

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,35 @@
1616
"oauth.microsoftgraph.SavePhoto": "true",
1717
"oauth.microsoftgraph.SavePhotoSize": "32x32",
1818
"NavItems": [
19-
{ "path":"/", "label": "Home", "exact":true },
20-
{ "path":"/about", "label": "About" },
21-
{ "path":"/about/services", "label": "Services" },
22-
{ "path":"/contact", "label": "Contact",
19+
{ "href":"/", "label": "Home", "exact":true },
20+
{ "href":"/about", "label": "About" },
21+
{ "href":"/about/services", "label": "Services" },
22+
{ "href":"/contact", "label": "Contact",
2323
"children": [
24-
{ "path": "/contact/me", "label":"Me" },
25-
{ "path": "/contact/email", "label":"Email" },
24+
{ "href": "/contact/me", "label":"Me" },
25+
{ "href": "/contact/email", "label":"Email" },
2626
{ "label":"-" },
27-
{ "path": "/contact/phone", "label":"Phone" }
27+
{ "href": "/contact/phone", "label":"Phone" }
2828
]
29-
}
29+
},
30+
{ "href":"/validation/server/login", "label": "Sign In", "hide": "auth" },
31+
{ "href":"/validation/server/register", "label": "Sign Up", "hide": "auth" },
32+
{ "href":"/account", "label": "My Account", "show": "auth" },
33+
{ "href":"/admin", "label": "Admin", "show": "role:Admin" }
3034
],
3135
"NavItemsMap": {
3236
"aside": [
33-
{ "path":"/aside", "label":"Aside" }
37+
{ "href":"/aside", "label":"Aside" }
3438
],
3539
"footer": [
36-
{ "path":"/terms", "label":"Terms" },
37-
{ "path":"/privacy", "label":"Privacy" },
38-
{ "path":"/contacts", "label": "Contacts",
40+
{ "href":"/terms", "label":"Terms" },
41+
{ "href":"/privacy", "label":"Privacy" },
42+
{ "href":"/contacts", "label": "Contacts",
3943
"children": [
40-
{ "path": "/contact/me", "label":"Me" },
41-
{ "path": "/contact/email", "label":"Email" },
44+
{ "href": "/contact/me", "label":"Me" },
45+
{ "href": "/contact/email", "label":"Email" },
4246
{ "label":"-" },
43-
{ "path": "/contact/phone", "label":"Phone" }
47+
{ "href": "/contact/phone", "label":"Phone" }
4448
]
4549
}
4650
]

tests/CheckWebCore/wwwroot/_layout.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
77
<meta name="description" content="">
88
<meta name="author" content="">
9+
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css" integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
10+
11+
912

1013
{{#if debug}}<script>{{ '/js/hot-loader.js' | includeFile }}</script>{{/if}}
1114

0 commit comments

Comments
 (0)