Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed generation of url with optional parameter and without default value #523

Merged
merged 5 commits into from
Dec 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/DotVVM.Framework/Controls/RouteLinkHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ private static string GenerateRouteLinkCore(string routeName, RouteLink control,
// generate the function call

return
parametersExpression.Length > 0 ? $"dotvvm.buildRouteUrl({JsonConvert.ToString(route.Url)}, {{{parametersExpression}}})" :
JsonConvert.ToString(route.Url);
route.ParameterNames.Any()
? $"dotvvm.buildRouteUrl({JsonConvert.ToString(route.Url)}, {{{parametersExpression}}})"
: JsonConvert.ToString(route.Url);
}

private static string TranslateRouteParameter(DotvvmBindableObject control, KeyValuePair<string, object> param, bool caseSensitive = false)
Expand Down
6 changes: 4 additions & 2 deletions src/DotVVM.Framework/Resources/Scripts/DotVVM.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/DotVVM.Framework/Resources/Scripts/DotVVM.min.js

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions src/DotVVM.Framework/Resources/Scripts/DotVVM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -930,10 +930,13 @@ class DotVVM {
return ko.unwrap(ko.unwrap(array));
}
public buildRouteUrl(routePath: string, params: any): string {
var url = routePath.replace(/\{([^\}]+?)\??(:(.+?))?\}/g, (s, paramName, hsjdhsj, type) => {
// prepend url with backslash to correctly handle optional parameters at start
routePath = '/' + routePath;

var url = routePath.replace(/(\/[^\/]*?)\{([^\}]+?)\??(:(.+?))?\}/g, (s, prefix, paramName, _, type) => {
if (!paramName) return "";
const x = ko.unwrap(params[paramName.toLowerCase()])
return x == null ? "" : x;
return x == null ? "" : prefix + x;
});

if (url.indexOf('/') === 0) {
Expand Down
3 changes: 3 additions & 0 deletions src/DotVVM.Samples.Common/DotvvmStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ private static void AddRoutes(DotvvmConfiguration config)
config.RouteTable.Add("FeatureSamples_ParameterBinding_OptionalParameterBinding2", "FeatureSamples/ParameterBinding/OptionalParameterBinding2/{Id?}", "Views/FeatureSamples/ParameterBinding/OptionalParameterBinding.dothtml", new { Id = 300 });
config.RouteTable.AutoDiscoverRoutes(new DefaultRouteStrategy(config));
config.RouteTable.Add("RepeaterRouteLink-PageDetail", "ControlSamples/Repeater/RouteLink/{Id}", "Views/ControlSamples/Repeater/RouteLink.dothtml", new { Id = 0 });
config.RouteTable.Add("RepeaterRouteLink-PageDetail_IdOptional", "ControlSamples/Repeater/RouteLink/{Id?}", "Views/ControlSamples/Repeater/RouteLink.dothtml");
config.RouteTable.Add("RepeaterRouteLink-PageDetail_IdOptionalPrefixed", "ControlSamples/Repeater/RouteLink/id-{Id?}", "Views/ControlSamples/Repeater/RouteLink.dothtml");
config.RouteTable.Add("RepeaterRouteLink-PageDetail_IdOptionalAtStart", "id-{Id?}/ControlSamples/Repeater/RouteLink", "Views/ControlSamples/Repeater/RouteLink.dothtml");
config.RouteTable.Add("RepeaterRouteLinkUrlSuffix-PageDetail", "ControlSamples/Repeater/RouteLinkUrlSuffix/{Id}", "Views/ControlSamples/Repeater/RouteLink.dothtml", new { Id = 0 });
config.RouteTable.Add("FeatureSamples_Redirect_RedirectFromPresenter", "FeatureSamples/Redirect/RedirectFromPresenter", provider => new RedirectingPresenter());
config.RouteTable.Add("FeatureSamples_Validation_ClientSideValidationDisabling2", "FeatureSamples/Validation/ClientSideValidationDisabling/{ClientSideValidationEnabled}", "Views/FeatureSamples/Validation/ClientSideValidationDisabling.dothtml", new { ClientSideValidationEnabled = false });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.RouteLink
{
public class RouteLinkUrlGenViewModel
{
public int RouteParameter { get; set; } = 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@
<div class="container">
<h1>RouteLink enabled property demo</h1>

<p>
<dot:CheckBox Checked="{value: Enabled}" Text="Enabled" />
</p>
<p>
<dot:RouteLink RouteName="RepeaterRouteLink-PageDetail" Param-Id="0" Enabled="{value: Enabled}" Text="Static href" />
</p>

<p>
<dot:RouteLink RouteName="RepeaterRouteLink-PageDetail" Param-Id="{value: RouteParameter}" Enabled="{value: Enabled}" Text="Dynamic href" />
</p>

<p>
<dot:CheckBox Checked="{value: Enabled}" Text="Enabled" />
</p>
<p>
<dot:RouteLink RouteName="RepeaterRouteLink-PageDetail" Param-Id="0" Enabled="{value: Enabled}" Text="Static href" />
</p>
<p>
<dot:RouteLink RouteName="RepeaterRouteLink-PageDetail" Param-Id="{value: RouteParameter}" Enabled="{value: Enabled}" Text="Dynamic href" />
</p>
</div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@viewModel DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.RouteLink.RouteLinkUrlGenViewModel

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Hello from DotVVM!</title>
<style>
.invalid {
color: red;
}
</style>
<dot:RequiredResource Name="globalize:cs-CZ" />
</head>
<body>
<div class="container">
<h1>RouteLink url generation demo</h1>
<p>
<dot:RouteLink RenderSettings.Mode="Client" RouteName="RepeaterRouteLink-PageDetail_IdOptional"
Text="Client rendered: Optional parameter" data-ui="optional-parameter-client" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Server" RouteName="RepeaterRouteLink-PageDetail_IdOptional"
Text="Server rendered: Optional parameter" data-ui="optional-parameter-server" />
</p>
<p>
<dot:RouteLink RouteName="Default" Text="0 parameters" data-ui="0-parameters" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Client" RouteName="RepeaterRouteLink-PageDetail_IdOptionalPrefixed"
Text="Client rendered: Optional parameter (Prefixed)" data-ui="optional-parameter-prefixed-client" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Server" RouteName="RepeaterRouteLink-PageDetail_IdOptionalPrefixed"
Text="Server rendered: Optional parameter (Prefixed)" data-ui="optional-parameter-prefixed-server" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Client" RouteName="RepeaterRouteLink-PageDetail_IdOptionalPrefixed" Param-Id="{value: RouteParameter}"
Text="Client rendered: Parameter (Prefixed)" data-ui="parameter-prefixed-client" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Server" RouteName="RepeaterRouteLink-PageDetail_IdOptionalPrefixed" Param-Id="{value: RouteParameter}"
Text="Server rendered: Parameter (Prefixed)" data-ui="parameter-prefixed-server" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Client" RouteName="RepeaterRouteLink-PageDetail_IdOptionalAtStart"
Text="Client rendered: Optional parameter (at start)" data-ui="optional-parameter-at-start-client" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Server" RouteName="RepeaterRouteLink-PageDetail_IdOptionalAtStart"
Text="Server rendered: Optional parameter (at start)" data-ui="optional-parameter-at-start-server" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Client" RouteName="RepeaterRouteLink-PageDetail_IdOptionalAtStart" Param-Id="{value: RouteParameter}"
Text="Client rendered: Optional prefixed parameter (at start)" data-ui="optional-prefixed-parameter-at-start-client" />
</p>
<p>
<dot:RouteLink RenderSettings.Mode="Server" RouteName="RepeaterRouteLink-PageDetail_IdOptionalAtStart" Param-Id="{value: RouteParameter}"
Text="Server rendered: Optional prefixed parameter (at start)" data-ui="optional-prefix-parameter-at-start-server" />
</p>
</div>
</body>
</html>
52 changes: 40 additions & 12 deletions src/DotVVM.Samples.Tests/Control/RouteLinkTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Testing.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Riganti.Selenium.Core.Abstractions;

namespace DotVVM.Samples.Tests.Control
{
Expand All @@ -16,34 +12,66 @@ public class RouteLinkTests : AppSeleniumTest
[SampleReference(nameof(SamplesRouteUrls.ControlSamples_RouteLink_TestRoute))]
public void Control_RouteLink_RouteLinkEnabled()
{
RunInAllBrowsers(browser =>
{
RunInAllBrowsers(browser => {
browser.NavigateToUrl(SamplesRouteUrls.ControlSamples_RouteLink_RouteLinkEnabled);
browser.Single("body > div.container > p:nth-child(2) > label > input[type=\"checkbox\"]")
.CheckIfIsNotChecked();
browser.Single("body > div.container > p:nth-child(3) > a").Click();

browser.Single("body > div.container > p:nth-child(2) > label > input[type=\"checkbox\"]").Click();
browser.Single("body > div.container > p:nth-child(3) > a").Click();
browser.CompareUrl("http://localhost:60320/ControlSamples/Repeater/RouteLink/0");
browser.CheckUrl("/ControlSamples/Repeater/RouteLink/0", UrlKind.Relative, UriComponents.PathAndQuery);
browser.NavigateBack();
});
}

[TestMethod]
[SampleReference(nameof(SamplesRouteUrls.ControlSamples_RouteLink_TestRoute))]
public void Control_RouteLink_RouteLinkUrlGeneration()
{
RunInAllBrowsers(browser => {
browser.NavigateToUrl(SamplesRouteUrls.ControlSamples_RouteLink_RouteLinkUrlGen);

void checkNavigatedUrl(string selector, string relativeUrl)
{
browser.Single(selector).Click();
browser.CheckUrl(relativeUrl, UrlKind.Relative, UriComponents.PathAndQuery);
browser.NavigateBack();
}

checkNavigatedUrl("a[data-ui='optional-parameter-client']", "/ControlSamples/Repeater/RouteLink");
checkNavigatedUrl("a[data-ui='optional-parameter-server']", "/ControlSamples/Repeater/RouteLink");

checkNavigatedUrl("a[data-ui='0-parameters']", "/");

checkNavigatedUrl("a[data-ui='optional-parameter-prefixed-client']", "/ControlSamples/Repeater/RouteLink");
checkNavigatedUrl("a[data-ui='optional-parameter-prefixed-server']", "/ControlSamples/Repeater/RouteLink");

checkNavigatedUrl("a[data-ui='parameter-prefixed-client']", "/ControlSamples/Repeater/RouteLink/id-1");
checkNavigatedUrl("a[data-ui='parameter-prefixed-server']", "/ControlSamples/Repeater/RouteLink/id-1");

checkNavigatedUrl("a[data-ui='optional-parameter-at-start-client']", "/ControlSamples/Repeater/RouteLink");
checkNavigatedUrl("a[data-ui='optional-parameter-at-start-server']", "/ControlSamples/Repeater/RouteLink");

checkNavigatedUrl("a[data-ui='optional-prefixed-parameter-at-start-client']", "/id-1/ControlSamples/Repeater/RouteLink");
checkNavigatedUrl("a[data-ui='optional-prefixed-parameter-at-start-client']", "/id-1/ControlSamples/Repeater/RouteLink");
});
}

[TestMethod]
[SampleReference(nameof(SamplesRouteUrls.ControlSamples_RouteLink_TestRoute))]
public void Control_RouteLink_RouteLinkEnabledFalse()
{
RunInAllBrowsers(browser =>
{
RunInAllBrowsers(browser => {
browser.NavigateToUrl(SamplesRouteUrls.ControlSamples_RouteLink_RouteLinkEnabledFalse);

//this RouteLink does not contain a binding (<dot:RouteLink Enabled="false" ... ) and should not redirect
browser.First("a").Click();
browser.CompareUrl("http://localhost:60320/ControlSamples/RouteLink/RouteLinkEnabledFalse");
browser.CheckUrl("/ControlSamples/RouteLink/RouteLinkEnabledFalse", UrlKind.Relative, UriComponents.PathAndQuery);

//this RouteLink contains a binding ( <dot:RouteLink Enabled={{value: "false" ... }} and should not redirect
browser.Last("a").Click();
browser.CompareUrl("http://localhost:60320/ControlSamples/RouteLink/RouteLinkEnabledFalse");
browser.CheckUrl("/ControlSamples/RouteLink/RouteLinkEnabledFalse", UrlKind.Relative, UriComponents.PathAndQuery);
});
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/DotVVM.Testing.Abstractions/SamplesRouteUrls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ public class SamplesRouteUrls{

public static string ControlSamples_RouteLink_RouteLinkEnabledFalse => "ControlSamples/RouteLink/RouteLinkEnabledFalse";

public static string ControlSamples_RouteLink_RouteLinkUrlGen => "ControlSamples/RouteLink/RouteLinkUrlGen";

public static string ControlSamples_RouteLink_TestRoute => "ControlSamples/RouteLink/TestRoute";

public static string ControlSamples_SpaContentPlaceHolder_Default => "ControlSamples/SpaContentPlaceHolder/Default";
Expand Down