Skip to content

Commit

Permalink
Add support for page-based routing in views, update server-js
Browse files Browse the repository at this point in the history
  • Loading branch information
mythz committed Feb 4, 2019
1 parent 83a2338 commit c8facee
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 34 deletions.
15 changes: 8 additions & 7 deletions src/ServiceStack/HttpHandlerFactory.cs
Expand Up @@ -290,20 +290,21 @@ public static IHttpHandler GetHandlerForPathInfo(IHttpRequest httpReq, string fi
: ForbiddenHttpHandler;
}

if (appHost.Config.FallbackRestPath != null)
{
restPath = appHost.Config.FallbackRestPath(httpReq);
if (restPath != null)
return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType };
}

// Check for PagedBasedRouting before wildcard Fallback Service
foreach (var httpHandlerResolver in appHost.FallbackHandlersArray)
{
var httpHandler = httpHandlerResolver(httpMethod, pathInfo, filePath);
if (httpHandler != null)
return httpHandler;
}

if (appHost.Config.FallbackRestPath != null)
{
restPath = appHost.Config.FallbackRestPath(httpReq);
if (restPath != null)
return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType };
}

return null;
}

Expand Down
2 changes: 1 addition & 1 deletion src/ServiceStack/TemplateBootstrapFilters.cs
Expand Up @@ -222,7 +222,7 @@ public IRawString formControl(TemplateScopeContext scope, object inputAttrs, str
var cls = inline ? " custom-control-inline" : "";
sbInput.AppendLine($"<div class=\"custom-control custom-checkbox{cls}\">");
var inputId = name + "-" + kvp.Key;
var selected = selectedValues.Contains(formValue) || selectedValues.Contains(kvp.Key) ? " checked" : "";
var selected = kvp.Key == formValue || selectedValues.Contains(kvp.Key) ? " checked" : "";
sbInput.AppendLine($" <input type=\"checkbox\" id=\"{inputId}\" name=\"{name}\" value=\"{kvp.Key}\" class=\"form-check-input\"{selected}>");
sbInput.AppendLine($" <label class=\"form-check-label\" for=\"{inputId}\">{kvp.Value}</label>");
sbInput.AppendLine("</div>");
Expand Down
56 changes: 40 additions & 16 deletions src/ServiceStack/TemplatePagesFeature.cs
Expand Up @@ -447,6 +447,21 @@ public async Task<bool> ProcessRequestAsync(IRequest req, object dto, Stream out
}
}

TemplatePage layoutPage = null;
var layoutName = req.GetItem(Keywords.Template) as string;
Dictionary<string, object> args = null;

if (codePage == null && viewPage == null && explicitView != null)
{
if (PageBasedRoutingHandler(req.Verb, explicitView, null) is TemplatePageHandler pageHandler)
{
viewPage = pageHandler.Page;
args = pageHandler.Args;
if (layoutName == null)
layoutPage = pageHandler.LayoutPage;
}
}

if (codePage == null && viewPage == null)
return false;

Expand All @@ -455,14 +470,13 @@ public async Task<bool> ProcessRequestAsync(IRequest req, object dto, Stream out
else
await viewPage.Init();

var layoutName = req.GetItem(Keywords.Template) as string;
var layoutPage = codePage != null
layoutPage = layoutPage ?? (codePage != null
? Pages.ResolveLayoutPage(codePage, layoutName)
: Pages.ResolveLayoutPage(viewPage, layoutName);
: Pages.ResolveLayoutPage(viewPage, layoutName));

var handler = codePage != null
? (HttpAsyncTaskHandler)new TemplateCodePageHandler(codePage, layoutPage) { OutputStream = outputStream, Model = dto }
: new TemplatePageHandler(viewPage, layoutPage) { OutputStream = outputStream, Model = dto };
: new TemplatePageHandler(viewPage, layoutPage) { OutputStream = outputStream, Model = dto, Args = args };

await handler.ProcessRequestAsync(req, req.Response, req.OperationName);

Expand Down Expand Up @@ -810,8 +824,8 @@ public object Any(TemplatesAdmin request)

public class TemplatePageHandler : HttpAsyncTaskHandler
{
private TemplatePage page;
private TemplatePage layoutPage;
public TemplatePage Page { get; private set; }
public TemplatePage LayoutPage { get; private set; }
public Dictionary<string, object> Args { get; set; }
public object Model { get; set; }
public Stream OutputStream { get; set; }
Expand All @@ -827,21 +841,21 @@ public TemplatePageHandler(string pagePath, string layoutPath=null)
public TemplatePageHandler(TemplatePage page, TemplatePage layoutPage = null)
{
this.RequestName = !string.IsNullOrEmpty(page.VirtualPath) ? page.VirtualPath : nameof(TemplatePageHandler);
this.page = page;
this.layoutPage = layoutPage;
this.Page = page;
this.LayoutPage = layoutPage;
}

public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpRes, string operationName)
{
if (page == null && pagePath != null)
if (Page == null && pagePath != null)
{
var pages = httpReq.TryResolve<ITemplatePages>();
page = pages.GetPage(pagePath)
Page = pages.GetPage(pagePath)
?? throw new FileNotFoundException($"Template Page not found '{pagePath}'");

if (!string.IsNullOrEmpty(layoutPath))
{
layoutPage = pages.GetPage(layoutPath)
LayoutPage = pages.GetPage(layoutPath)
?? throw new FileNotFoundException($"Template Page not found '{layoutPath}'");
}
}
Expand All @@ -857,16 +871,16 @@ public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpR
}
}

var pageResult = new PageResult(page)
var pageResult = new PageResult(Page)
{
Args = args,
LayoutPage = layoutPage,
LayoutPage = LayoutPage,
Model = Model,
};

try
{
httpRes.ContentType = page.Format.ContentType;
httpRes.ContentType = Page.Format.ContentType;
if (OutputStream != null)
{
await pageResult.WriteToAsync(OutputStream);
Expand Down Expand Up @@ -900,7 +914,7 @@ public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpR
}
catch (Exception ex)
{
await page.Format.OnViewException(pageResult, httpReq, ex);
await Page.Format.OnViewException(pageResult, httpReq, ex);
}
}
}
Expand All @@ -911,6 +925,8 @@ public class TemplateCodePageHandler : HttpAsyncTaskHandler
private readonly TemplatePage layoutPage;
public object Model { get; set; }
public Stream OutputStream { get; set; }

public Dictionary<string, object> Args { get; set; }

public TemplateCodePageHandler(TemplateCodePage page, TemplatePage layoutPage = null)
{
Expand All @@ -933,6 +949,14 @@ public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpR
Model = Model,
};

if (Args != null)
{
foreach (var entry in Args)
{
result.Args[entry.Key] = entry.Value;
}
}

try
{
httpRes.ContentType = page.Format.ContentType;
Expand Down
4 changes: 2 additions & 2 deletions tests/CheckWebCore/wwwroot/_layout.html
Expand Up @@ -29,10 +29,10 @@ <h3>MyApp</h3>
</nav>

<!-- Page Content -->
<div class="container">
<div class="container" style="padding: 1em 0">
<div class="row">
<div class="col-lg-12">
<h1 class="mt-5">{{ title }}</h1>
{{#if title}}<h1 class="mt-5">{{ title }}</h1>{{/if}}
{{ page }}
</div>
</div>
Expand Down
Expand Up @@ -2,13 +2,13 @@

{{ '/validation/server-js/contacts/' | assignTo: continue }}

{{ { Id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }}
{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }}

{{#with response.Result}}
<h3>Update Contact</h3>

<form action="/contacts/{{Id}}" method="post" class="col-lg-4">
<div class="form-group" data-validation-summary="title,name,color,age"></div>
<div class="form-group" data-validation-summary="title,name,color,filmGenres,age"></div>

<div class="form-group">
<div class="form-check">
Expand All @@ -35,7 +35,19 @@ <h3>Update Contact</h3>
</select>
</div>
<div class="form-group">
<input class="form-control col-2" name="age" type="text" placeholder="Age" value="{{Age}}">
<label class="form-check-label">Favorite Film Genres</label>
<div class="form-check">
{{#each contactGenres}}
<div class="custom-control custom-checkbox">
<input type="checkbox" id="filmGenres-{{it}}" name="filmGenres" value="{{it}}" class="form-check-input"
{{ {checked:any(FilmGenres,x => x == toString(it))} | htmlAttrs }}>
<label class="form-check-label" for="filmGenres-{{it}}">{{it}}</label>
</div>
{{/each}}
</div>
</div>
<div class="form-group">
<input class="form-control col-3" name="age" type="number" min="3" placeholder="Age" value="{{Age}}">
</div>
<div class="form-group">
<button class="btn btn-primary" type="submit">Update Contact</button>
Expand Down
Expand Up @@ -30,7 +30,18 @@ <h3>Add new Contact</h3>
</select>
</div>
<div class="form-group">
<input class="form-control col-2" name="age" type="text" placeholder="Age">
<label class="form-check-label">Favorite Film Genres</label>
<div class="form-check">
{{#each contactGenres}}
<div class="custom-control custom-checkbox">
<input type="checkbox" id="filmGenres-{{it}}" name="filmGenres" value="{{it}}" class="form-check-input">
<label class="form-check-label" for="filmGenres-{{it}}">{{it}}</label>
</div>
{{/each}}
</div>
</div>
<div class="form-group">
<input class="form-control col-3" name="age" type="number" min="13" placeholder="Age">
</div>
<div class="form-group">
<div class="form-check">
Expand Down Expand Up @@ -75,7 +86,7 @@ <h3>Add new Contact</h3>
function contactRow(contact) {
return '<tr style="background:' + contact.color + '">' +
'<td>' + contact.title + ' ' + contact.name + ' (' + contact.age + ')</td>' +
'<td><a href="/validation/server-js/contacts/edit?Id=' + contact.id + '">edit</a></td>' +
'<td><a href="/validation/server-js/contacts/' + contact.id + '/edit">edit</a></td>' +
'<td><button class="btn btn-sm btn-primary" data-click="deleteContact:' + contact.id + '">delete</button></td>' +
'</tr>';
}
Expand Down
Expand Up @@ -2,15 +2,15 @@

{{ '/validation/server/contacts/' | assignTo: continue }}

{{ { Id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }}
{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }}

{{#with response.Result}}
<h3>Update Contact</h3>

<form action="/contacts/{{Id}}" method="post" class="col-lg-4">
<div class="form-group">
{{ 'title,name,color,filmGenres,age' | validationSummary }}
{{ {Id,continue,errorView:"/validation/server/contacts/edit"} | htmlHiddenInputs }}
{{ {continue,errorView:`/validation/server/contacts/${id}/edit`} | htmlHiddenInputs }}
</div>
<div class="form-group">
{{ {id:'title',type:'radio',value:Title} | formInput({values:contactTitles,inline:true}) }}
Expand Down
Expand Up @@ -38,7 +38,7 @@ <h3>Add new Contact</h3>
{{#each response.Results}}
<tr style="background:{{Color}}">
<td>{{Title}} {{Name}} ({{Age}})</td>
<td><a href="/validation/server/contacts/edit?Id={{Id}}">edit</a></td>
<td><a href="/validation/server/contacts/{{Id}}/edit">edit</a></td>
<td><form method="post" action="/contacts/{{Id}}/delete" onsubmit="return confirm('Are you sure?')">
<button class="btn btn-sm btn-primary">delete</button></form></td>
</tr>
Expand Down

0 comments on commit c8facee

Please sign in to comment.