Normalise trailing whitespace and line endings everywhere

This commit is contained in:
SteveSandersonMS
2016-03-01 01:10:43 +00:00
parent c425137423
commit 74cac774f8
174 changed files with 782 additions and 783 deletions

4
.gitattributes vendored
View File

@@ -13,7 +13,7 @@
*.png binary *.png binary
*.gif binary *.gif binary
*.cs text=auto diff=csharp *.cs text=auto diff=csharp
*.vb text=auto *.vb text=auto
*.resx text=auto *.resx text=auto
*.c text=auto *.c text=auto
@@ -48,4 +48,4 @@
*.fsproj text=auto *.fsproj text=auto
*.dbproj text=auto *.dbproj text=auto
*.sln text=auto eol=crlf *.sln text=auto eol=crlf
*.sh eol=lf *.sh eol=lf

View File

@@ -17,4 +17,4 @@ os:
- osx - osx
osx_image: xcode7.1 osx_image: xcode7.1
script: script:
- ./build.sh verify - ./build.sh verify

View File

@@ -5,4 +5,4 @@
<add key="AspNetVNext" value="https://www.myget.org/f/aspnetmaster/api/v3/index.json" /> <add key="AspNetVNext" value="https://www.myget.org/f/aspnetmaster/api/v3/index.json" />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" /> <add key="NuGet" value="https://api.nuget.org/v3/index.json" />
</packageSources> </packageSources>
</configuration> </configuration>

View File

@@ -91,7 +91,7 @@ Note that to run the React example, you'll also need to run `webpack` from the `
``` ```
4. Where applicable, build the project. For example, the Angular example uses Gulp, so you'll need to execute `gulp`, whereas the React example uses Webpack, so you'll need to execute `webpack`. The ES2015 example does not need to be built. 4. Where applicable, build the project. For example, the Angular example uses Gulp, so you'll need to execute `gulp`, whereas the React example uses Webpack, so you'll need to execute `webpack`. The ES2015 example does not need to be built.
If you don't already have it, install the applicable build tool first (e.g., `npm install -g webpack`). If you don't already have it, install the applicable build tool first (e.g., `npm install -g webpack`).
5. Run the project (and wait until it displays the message `Application started`) 5. Run the project (and wait until it displays the message `Application started`)

View File

@@ -4,4 +4,4 @@ build_script:
- build.cmd verify - build.cmd verify
clone_depth: 1 clone_depth: 1
test: off test: off
deploy: off deploy: off

View File

@@ -27,4 +27,4 @@ namespace MusicStore.Apis
return Json(artists); return Json(artists);
} }
} }
} }

View File

@@ -67,4 +67,4 @@ namespace MusicStore.Apis
return Json(albums); return Json(albums);
} }
} }
} }

View File

@@ -60,4 +60,4 @@ namespace MusicStore.Models
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; } public string ConfirmPassword { get; set; }
} }
} }

View File

@@ -7,7 +7,7 @@ namespace MusicStore.Models
{ {
public Album() public Album()
{ {
// TODO: Temporary hack to populate the orderdetails until EF does this automatically. // TODO: Temporary hack to populate the orderdetails until EF does this automatically.
OrderDetails = new List<OrderDetail>(); OrderDetails = new List<OrderDetail>();
} }
@@ -37,4 +37,4 @@ namespace MusicStore.Models
public virtual ICollection<OrderDetail> OrderDetails { get; set; } public virtual ICollection<OrderDetail> OrderDetails { get; set; }
} }
} }

View File

@@ -9,4 +9,4 @@ namespace MusicStore.Models
[Required] [Required]
public string Name { get; set; } public string Name { get; set; }
} }
} }

View File

@@ -18,4 +18,4 @@ namespace MusicStore.Models
public virtual Album Album { get; set; } public virtual Album Album { get; set; }
} }
} }

View File

@@ -21,4 +21,4 @@ namespace MusicStore.Models
[JsonIgnore] [JsonIgnore]
public virtual ICollection<Album> Albums { get; set; } public virtual ICollection<Album> Albums { get; set; }
} }
} }

View File

@@ -31,4 +31,4 @@ namespace MusicStore.Models
base.OnModelCreating(builder); base.OnModelCreating(builder);
} }
} }
} }

View File

@@ -70,4 +70,4 @@ namespace MusicStore.Models
public ICollection<OrderDetail> OrderDetails { get; set; } public ICollection<OrderDetail> OrderDetails { get; set; }
} }
} }

View File

@@ -11,4 +11,4 @@
public virtual Album Album { get; set; } public virtual Album Album { get; set; }
public virtual Order Order { get; set; } public virtual Order Order { get; set; }
} }
} }

View File

@@ -42,13 +42,13 @@ namespace MusicStore.Models
{ {
// Query in a separate context so that we can attach existing entities as modified // Query in a separate context so that we can attach existing entities as modified
List<TEntity> existingData; List<TEntity> existingData;
using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
using (var db = scope.ServiceProvider.GetService<MusicStoreContext>()) using (var db = scope.ServiceProvider.GetService<MusicStoreContext>())
{ {
existingData = db.Set<TEntity>().ToList(); existingData = db.Set<TEntity>().ToList();
} }
using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
using (var db = scope.ServiceProvider.GetService<MusicStoreContext>()) using (var db = scope.ServiceProvider.GetService<MusicStoreContext>())
{ {
@@ -65,8 +65,8 @@ namespace MusicStore.Models
private static Album[] GetAlbums(string imgUrl, Dictionary<string, Genre> genres, Dictionary<string, Artist> artists) private static Album[] GetAlbums(string imgUrl, Dictionary<string, Genre> genres, Dictionary<string, Artist> artists)
{ {
var albums = new Album[] var albums = new Album[]
{ {
new Album { Title = "The Best Of The Men At Work", Genre = genres["Pop"], Price = 8.99M, Artist = artists["Men At Work"], AlbumArtUrl = imgUrl }, new Album { Title = "The Best Of The Men At Work", Genre = genres["Pop"], Price = 8.99M, Artist = artists["Men At Work"], AlbumArtUrl = imgUrl },
new Album { Title = "...And Justice For All", Genre = genres["Metal"], Price = 8.99M, Artist = artists["Metallica"], AlbumArtUrl = imgUrl }, new Album { Title = "...And Justice For All", Genre = genres["Metal"], Price = 8.99M, Artist = artists["Metallica"], AlbumArtUrl = imgUrl },
new Album { Title = "עד גבול האור", Genre = genres["World"], Price = 8.99M, Artist = artists["אריק אינשטיין"], AlbumArtUrl = imgUrl }, new Album { Title = "עד גבול האור", Genre = genres["World"], Price = 8.99M, Artist = artists["אריק אינשטיין"], AlbumArtUrl = imgUrl },
@@ -912,4 +912,4 @@ namespace MusicStore.Models
} }
} }
} }
} }

View File

@@ -8,9 +8,9 @@ namespace MusicStore.Models
public static class SentimentAnalysis public static class SentimentAnalysis
{ {
private static string[] positiveSentimentWords = new[] { "happy", "fun", "joy", "love", "delight", "bunny", "bunnies", "asp.net" }; private static string[] positiveSentimentWords = new[] { "happy", "fun", "joy", "love", "delight", "bunny", "bunnies", "asp.net" };
private static string[] negativeSentimentWords = new[] { "sad", "pain", "despair", "hate", "scorn", "death", "package management" }; private static string[] negativeSentimentWords = new[] { "sad", "pain", "despair", "hate", "scorn", "death", "package management" };
public static SentimentResult GetSentiment(string text) { public static SentimentResult GetSentiment(string text) {
var numPositiveWords = CountWordOccurrences(text, positiveSentimentWords); var numPositiveWords = CountWordOccurrences(text, positiveSentimentWords);
var numNegativeWords = CountWordOccurrences(text, negativeSentimentWords); var numNegativeWords = CountWordOccurrences(text, negativeSentimentWords);
@@ -35,4 +35,4 @@ namespace MusicStore.Models
Positive, Positive,
} }
} }
} }

View File

@@ -123,7 +123,7 @@ namespace MusicStore.Models
public decimal GetTotal() public decimal GetTotal()
{ {
// Multiply album price by count of that album to get // Multiply album price by count of that album to get
// the current price for each of those albums in the cart // the current price for each of those albums in the cart
// sum all album price totals to get the cart total // sum all album price totals to get the cart total
@@ -190,7 +190,7 @@ namespace MusicStore.Models
if (string.IsNullOrWhiteSpace(sessionCookie)) if (string.IsNullOrWhiteSpace(sessionCookie))
{ {
//A GUID to hold the cartId. //A GUID to hold the cartId.
cartId = Guid.NewGuid().ToString(); cartId = Guid.NewGuid().ToString();
// Send cart Id as a cookie to the client. // Send cart Id as a cookie to the client.
@@ -204,4 +204,4 @@ namespace MusicStore.Models
return cartId; return cartId;
} }
} }
} }

View File

@@ -16,4 +16,4 @@ namespace MusicStore.Infrastructure
base.OnResultExecuting(context); base.OnResultExecuting(context);
} }
} }
} }

View File

@@ -147,4 +147,4 @@ namespace MusicStore.Infrastructure
public int PageSize { get; set; } public int PageSize { get; set; }
} }
} }
} }

View File

@@ -16,4 +16,4 @@
<DevelopmentServerPort>5068</DevelopmentServerPort> <DevelopmentServerPort>5068</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -44,7 +44,7 @@ namespace MusicStore
// Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers. // Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers.
// You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json. // You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json.
// services.AddWebApiConventions(); // services.AddWebApiConventions();
// Add EF services to the service container // Add EF services to the service container
services.AddEntityFramework() services.AddEntityFramework()
.AddSqlite() .AddSqlite()
@@ -82,7 +82,7 @@ namespace MusicStore
{ {
// Initialize the sample data // Initialize the sample data
SampleData.InitializeMusicStoreDatabaseAsync(app.ApplicationServices).Wait(); SampleData.InitializeMusicStoreDatabaseAsync(app.ApplicationServices).Wait();
loggerFactory.MinimumLevel = LogLevel.Warning; loggerFactory.MinimumLevel = LogLevel.Warning;
loggerFactory.AddConsole(); loggerFactory.AddConsole();
loggerFactory.AddDebug(); loggerFactory.AddDebug();
@@ -103,7 +103,7 @@ namespace MusicStore
// send the request to the following path or controller action. // send the request to the following path or controller action.
app.UseExceptionHandler("/Home/Error"); app.UseExceptionHandler("/Home/Error");
} }
// Add static files to the request pipeline. // Add static files to the request pipeline.
app.UseStaticFiles(); app.UseStaticFiles();
@@ -112,7 +112,7 @@ namespace MusicStore
{ {
// Matches requests that correspond to an existent controller/action pair // Matches requests that correspond to an existent controller/action pair
routes.MapRoute("default", "{controller}/{action}/{id:int?}"); routes.MapRoute("default", "{controller}/{action}/{id:int?}");
// Matches any other request that doesn't appear to have a filename extension (defined as 'having a dot in the last URI segment'). // Matches any other request that doesn't appear to have a filename extension (defined as 'having a dot in the last URI segment').
// This means you'll correctly get 404s for /some/dir/non-existent-image.png instead of returning the SPA HTML. // This means you'll correctly get 404s for /some/dir/non-existent-image.png instead of returning the SPA HTML.
// However, it means requests like /customers/isaac.newton will *not* be mapped into the SPA, so if you need to accept // However, it means requests like /customers/isaac.newton will *not* be mapped into the SPA, so if you need to accept

View File

@@ -1,26 +1,26 @@
@{ @{
ViewData["Title"] = "Home Page"; ViewData["Title"] = "Home Page";
} }
<cache vary-by="@Context.Request.Path"> <cache vary-by="@Context.Request.Path">
<app asp-ng2-prerender-module="wwwroot/ng-app/components/app/app"> <app asp-ng2-prerender-module="wwwroot/ng-app/components/app/app">
Loading... Loading...
</app> </app>
</cache> </cache>
@section scripts { @section scripts {
@await Html.PrimeCache(Url.Action("GenreMenuList", "GenresApi")) @await Html.PrimeCache(Url.Action("GenreMenuList", "GenresApi"))
@await Html.PrimeCache(Url.Action("MostPopular", "AlbumsApi")) @await Html.PrimeCache(Url.Action("MostPopular", "AlbumsApi"))
<script src="~/lib/angular2/bundles/angular2-polyfills.js"></script> <script src="~/lib/angular2/bundles/angular2-polyfills.js"></script>
<script src="~/lib/traceur/bin/traceur-runtime.js"></script> <script src="~/lib/traceur/bin/traceur-runtime.js"></script>
<script src="~/lib/es6-module-loader/dist/es6-module-loader-sans-promises.js"></script> <script src="~/lib/es6-module-loader/dist/es6-module-loader-sans-promises.js"></script>
<script src="~/lib/systemjs/dist/system.src.js"></script> <script src="~/lib/systemjs/dist/system.src.js"></script>
<script src="~/system.config.js"></script> <script src="~/system.config.js"></script>
<script src="~/lib/rxjs/bundles/Rx.js"></script> <script src="~/lib/rxjs/bundles/Rx.js"></script>
<script src="~/lib/angular2/bundles/angular2.dev.js"></script> <script src="~/lib/angular2/bundles/angular2.dev.js"></script>
<script src="~/lib/angular2/bundles/router.dev.js"></script> <script src="~/lib/angular2/bundles/router.dev.js"></script>
<script src="~/lib/angular2/bundles/http.dev.js"></script> <script src="~/lib/angular2/bundles/http.dev.js"></script>
<script src="~/lib/angular2-aspnet/bundles/angular2-aspnet.js"></script> <script src="~/lib/angular2-aspnet/bundles/angular2-aspnet.js"></script>
<script>System.import('./ng-app/components/app/bootstrap');</script> <script>System.import('./ng-app/components/app/bootstrap');</script>
} }

View File

@@ -1,6 +1,6 @@
@{ @{
ViewData["Title"] = "Error"; ViewData["Title"] = "Error";
} }
<h1 class="text-danger">Error.</h1> <h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2> <h2 class="text-danger">An error occurred while processing your request.</h2>

View File

@@ -1,40 +1,40 @@
<!doctype html> <!doctype html>
<html lang=""> <html lang="">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Music Store</title> <title>Music Store</title>
<base href="/" /> <base href="/" />
<environment names="Development"> <environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" /> <link rel="stylesheet" href="~/css/site.css" />
</environment> </environment>
<environment names="Staging,Production"> <environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/css/bootstrap.min.css" <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="hidden" asp-fallback-test-property="visibility" asp-fallback-test-value="hidden" /> asp-fallback-test-class="hidden" asp-fallback-test-property="visibility" asp-fallback-test-value="hidden" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</environment> </environment>
</head> </head>
<body> <body>
@RenderBody() @RenderBody()
<environment names="Development"> <environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
</environment> </environment>
<environment names="Staging,Production"> <environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js" <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js" asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"> asp-fallback-test="window.jQuery">
</script> </script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/bootstrap.min.js" <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.0.0/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js" asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"> asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
</script> </script>
</environment> </environment>
@RenderSection("scripts", required: false) @RenderSection("scripts", required: false)
</body> </body>
</html> </html>

View File

@@ -1,4 +1,4 @@
@using MusicStore @using MusicStore
@using Microsoft.AspNet.AngularServices @using Microsoft.AspNet.AngularServices
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*, Microsoft.AspNet.AngularServices" @addTagHelper "*, Microsoft.AspNet.AngularServices"

View File

@@ -1,3 +1,3 @@
@{ @{
Layout = "_Layout"; Layout = "_Layout";
} }

View File

@@ -44,4 +44,4 @@
"gulp" "gulp"
] ]
} }
} }

View File

@@ -17,5 +17,5 @@ import { AlbumEdit } from '../album-edit/album-edit';
directives: [router.ROUTER_DIRECTIVES] directives: [router.ROUTER_DIRECTIVES]
}) })
export class AdminHome { export class AdminHome {
} }

View File

@@ -9,13 +9,13 @@ import * as models from '../../../models/models';
}) })
export class AlbumDeletePrompt { export class AlbumDeletePrompt {
public album: models.Album; public album: models.Album;
constructor(@ng.Inject(ng.ElementRef) private _elementRef: ng.ElementRef) { constructor(@ng.Inject(ng.ElementRef) private _elementRef: ng.ElementRef) {
} }
public show(album: models.Album) { public show(album: models.Album) {
this.album = album; this.album = album;
// Consider rewriting this using Angular 2's "Renderer" API so as to avoid direct DOM access // Consider rewriting this using Angular 2's "Renderer" API so as to avoid direct DOM access
(<any>window).jQuery(".modal", this._elementRef.nativeElement).modal(); (<any>window).jQuery(".modal", this._elementRef.nativeElement).modal();
} }

View File

@@ -47,4 +47,4 @@
</div> </div>
</form> </form>
<album-delete-prompt #deleteprompt></album-delete-prompt> <album-delete-prompt #deleteprompt></album-delete-prompt>

View File

@@ -13,7 +13,7 @@ import { AlbumDeletePrompt } from '../album-delete-prompt/album-delete-prompt';
}) })
export class AlbumDetails { export class AlbumDetails {
public albumData: models.Album; public albumData: models.Album;
constructor(http: Http, routeParam: router.RouteParams) { constructor(http: Http, routeParam: router.RouteParams) {
http.get('/api/albums/' + routeParam.params['albumId']).subscribe(result => { http.get('/api/albums/' + routeParam.params['albumId']).subscribe(result => {
this.albumData = result.json(); this.albumData = result.json();

View File

@@ -8,18 +8,18 @@
<option *ngFor="#artist of artists" [value]="artist.ArtistId">{{ artist.Name }}</option> <option *ngFor="#artist of artists" [value]="artist.ArtistId">{{ artist.Name }}</option>
</select> </select>
</form-field> </form-field>
<form-field label="Genre" [validate]="form.controls.GenreId"> <form-field label="Genre" [validate]="form.controls.GenreId">
<select class="form-control" ngControl="GenreId"> <select class="form-control" ngControl="GenreId">
<option value="0">-- choose Genre --</option> <option value="0">-- choose Genre --</option>
<option *ngFor="#genre of genres" [value]="genre.GenreId">{{ genre.Name }}</option> <option *ngFor="#genre of genres" [value]="genre.GenreId">{{ genre.Name }}</option>
</select> </select>
</form-field> </form-field>
<form-field label="Title" [validate]="form.controls.Title"> <form-field label="Title" [validate]="form.controls.Title">
<input class="form-control" type="text" ngControl="Title"> <input class="form-control" type="text" ngControl="Title">
</form-field> </form-field>
<form-field label="Price" [validate]="form.controls.Price"> <form-field label="Price" [validate]="form.controls.Price">
<div class="input-group"> <div class="input-group">
<span class="input-group-addon">$</span> <span class="input-group-addon">$</span>
@@ -30,7 +30,7 @@
<form-field label="Album Art URL" [validate]="form.controls.AlbumArtUrl"> <form-field label="Album Art URL" [validate]="form.controls.AlbumArtUrl">
<input class="form-control" ngControl="AlbumArtUrl"> <input class="form-control" ngControl="AlbumArtUrl">
</form-field> </form-field>
<form-field label="Album Art"> <form-field label="Album Art">
<img src="{{ form.controls.AlbumArtUrl.value }}"> <img src="{{ form.controls.AlbumArtUrl.value }}">
</form-field> </form-field>
@@ -44,4 +44,4 @@
</form-field> </form-field>
</form> </form>
<album-delete-prompt #deleteprompt></album-delete-prompt> <album-delete-prompt #deleteprompt></album-delete-prompt>

View File

@@ -55,7 +55,7 @@ export class AlbumEdit {
Price: fb.control('', Validators.compose([Validators.required, AlbumEdit._validatePrice])), Price: fb.control('', Validators.compose([Validators.required, AlbumEdit._validatePrice])),
AlbumArtUrl: fb.control('', Validators.required) AlbumArtUrl: fb.control('', Validators.required)
}); });
this.form.valueChanges.subscribe(() => { this.form.valueChanges.subscribe(() => {
this.changesSaved = false; this.changesSaved = false;
}); });
@@ -70,7 +70,7 @@ export class AlbumEdit {
if (this.form.valid) { if (this.form.valid) {
var controls = this.form.controls; var controls = this.form.controls;
var albumId = this.originalAlbum.AlbumId; var albumId = this.originalAlbum.AlbumId;
this._putJson(`/api/albums/${ albumId }/update`, this.form.value).subscribe(successResponse => { this._putJson(`/api/albums/${ albumId }/update`, this.form.value).subscribe(successResponse => {
this.changesSaved = true; this.changesSaved = true;
}, errorResponse => { }, errorResponse => {
@@ -82,7 +82,7 @@ export class AlbumEdit {
private static _validatePrice(control: Control): { [key: string]: boolean } { private static _validatePrice(control: Control): { [key: string]: boolean } {
return /^\d+\.\d+$/.test(control.value) ? null : { Price: true }; return /^\d+\.\d+$/.test(control.value) ? null : { Price: true };
} }
// Need feedback on whether this really is the easiest way to PUT some JSON // Need feedback on whether this really is the easiest way to PUT some JSON
private _putJson(url: string, body: any): Observable<Response> { private _putJson(url: string, body: any): Observable<Response> {
return this._http.put(url, JSON.stringify(body), { return this._http.put(url, JSON.stringify(body), {
@@ -93,4 +93,4 @@ export class AlbumEdit {
private ngDoCheck() { private ngDoCheck() {
this.formErrors = this.form.dirty ? Object.keys(this.form.errors || {}) : []; this.formErrors = this.form.dirty ? Object.keys(this.form.errors || {}) : [];
} }
} }

View File

@@ -32,7 +32,7 @@
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-default" [disabled]="!canGoBack" (click)="goToPage(1)">First</button> <button class="btn btn-default" [disabled]="!canGoBack" (click)="goToPage(1)">First</button>
<button class="btn btn-default" [disabled]="!canGoBack" (click)="goToPage(pageIndex - 1)">Previous</button> <button class="btn btn-default" [disabled]="!canGoBack" (click)="goToPage(pageIndex - 1)">Previous</button>
<button class="btn" *ngFor="#page of pageLinks" <button class="btn" *ngFor="#page of pageLinks"
[ngClass]="{ 'btn-info': page.isCurrent, 'btn-default': !page.isCurrent }" [ngClass]="{ 'btn-info': page.isCurrent, 'btn-default': !page.isCurrent }"
(click)="goToPage(page.index)"> (click)="goToPage(page.index)">
{{ page.text }} {{ page.text }}

View File

@@ -20,7 +20,7 @@ export class AlbumsList {
public get pageIndex() { public get pageIndex() {
return this._pageIndex; return this._pageIndex;
} }
private _http: Http; private _http: Http;
private _pageIndex = 1; private _pageIndex = 1;
private _sortBy = "Title"; private _sortBy = "Title";
@@ -30,28 +30,28 @@ export class AlbumsList {
this._http = http; this._http = http;
this.refreshData(); this.refreshData();
} }
public sortBy(col: string) { public sortBy(col: string) {
this._sortByDesc = col === this._sortBy ? !this._sortByDesc : false; this._sortByDesc = col === this._sortBy ? !this._sortByDesc : false;
this._sortBy = col; this._sortBy = col;
this.refreshData(); this.refreshData();
} }
public goToPage(pageIndex: number) { public goToPage(pageIndex: number) {
this._pageIndex = pageIndex; this._pageIndex = pageIndex;
this.refreshData(); this.refreshData();
} }
public goToLast() { public goToLast() {
this.goToPage(this.pageLinks[this.pageLinks.length - 1].index); this.goToPage(this.pageLinks[this.pageLinks.length - 1].index);
} }
refreshData() { refreshData() {
var sortBy = this._sortBy + (this._sortByDesc ? ' DESC' : ''); var sortBy = this._sortBy + (this._sortByDesc ? ' DESC' : '');
this._http.get(`/api/albums?page=${ this._pageIndex }&pageSize=50&sortBy=${ sortBy }`).subscribe(result => { this._http.get(`/api/albums?page=${ this._pageIndex }&pageSize=50&sortBy=${ sortBy }`).subscribe(result => {
var json = result.json(); var json = result.json();
this.rows = json.Data; this.rows = json.Data;
var numPages = Math.ceil(json.TotalCount / json.PageSize); var numPages = Math.ceil(json.TotalCount / json.PageSize);
this.pageLinks = []; this.pageLinks = [];
for (var i = 1; i <= numPages; i++) { for (var i = 1; i <= numPages; i++) {
@@ -61,7 +61,7 @@ export class AlbumsList {
isCurrent: i === json.Page isCurrent: i === json.Page
}); });
} }
this.canGoBack = this.pageLinks.length && !this.pageLinks[0].isCurrent; this.canGoBack = this.pageLinks.length && !this.pageLinks[0].isCurrent;
this.canGoForward = this.pageLinks.length && !this.pageLinks[this.pageLinks.length - 1].isCurrent; this.canGoForward = this.pageLinks.length && !this.pageLinks[this.pageLinks.length - 1].isCurrent;
this.totalCount = json.TotalCount; this.totalCount = json.TotalCount;

View File

@@ -11,7 +11,7 @@ import { AbstractControl } from 'angular2/common';
export class FormField { export class FormField {
public errorMessages: string[] = []; public errorMessages: string[] = [];
private validate: AbstractControl; private validate: AbstractControl;
private ngDoCheck() { private ngDoCheck() {
var errors = (this.validate && this.validate.dirty && this.validate.errors) || {}; var errors = (this.validate && this.validate.dirty && this.validate.errors) || {};
this.errorMessages = Object.keys(errors).map(key => { this.errorMessages = Object.keys(errors).map(key => {

View File

@@ -1,10 +1,10 @@
<div *ngIf="albumData"> <div *ngIf="albumData">
<h2>{{ albumData.Title }}</h2> <h2>{{ albumData.Title }}</h2>
<p> <p>
<img alt="{{ albumData.Title }}" src="{{ albumData.AlbumArtUrl }}"> <img alt="{{ albumData.Title }}" src="{{ albumData.AlbumArtUrl }}">
</p> </p>
<div id="album-details"> <div id="album-details">
<p> <p>
<em>Genre:</em> <em>Genre:</em>
@@ -23,4 +23,4 @@
Add to cart Add to cart
</p> </p>
</div> </div>
</div> </div>

View File

@@ -11,7 +11,7 @@ import * as models from '../../../models/models';
}) })
export class AlbumDetails { export class AlbumDetails {
public albumData: models.Album; public albumData: models.Album;
constructor(http: Http, routeParam: router.RouteParams) { constructor(http: Http, routeParam: router.RouteParams) {
http.get('/api/albums/' + routeParam.params['albumId']).subscribe(result => { http.get('/api/albums/' + routeParam.params['albumId']).subscribe(result => {
this.albumData = result.json(); this.albumData = result.json();

View File

@@ -16,7 +16,7 @@ export class GenreContents {
constructor(http: Http, routeParam: router.RouteParams) { constructor(http: Http, routeParam: router.RouteParams) {
http.get(`/api/genres/${ routeParam.params['genreId'] }/albums`).subscribe(result => { http.get(`/api/genres/${ routeParam.params['genreId'] }/albums`).subscribe(result => {
this.albums = result.json(); this.albums = result.json();
}); });
} }
} }

View File

@@ -15,7 +15,7 @@ export class GenresList {
constructor(http: Http) { constructor(http: Http) {
http.get('/api/genres').subscribe(result => { http.get('/api/genres').subscribe(result => {
this.genres = result.json(); this.genres = result.json();
}); });
} }
} }

View File

@@ -2,7 +2,7 @@ import * as ng from 'angular2/core';
import { Http } from 'angular2/http'; import { Http } from 'angular2/http';
import { AlbumTile } from '../album-tile/album-tile'; import { AlbumTile } from '../album-tile/album-tile';
import * as models from '../../../models/models'; import * as models from '../../../models/models';
@ng.Component({ @ng.Component({
selector: 'home' selector: 'home'
}) })
@@ -15,7 +15,7 @@ export class Home {
constructor(http: Http) { constructor(http: Http) {
http.get('/api/albums/mostPopular').subscribe(result => { http.get('/api/albums/mostPopular').subscribe(result => {
this.mostPopular = result.json(); this.mostPopular = result.json();
}); });
} }
} }

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<system.webServer> <system.webServer>
<handlers> <handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" /> <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers> </handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" forwardWindowsAuthToken="false" startupTimeLimit="3600" /> <httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" forwardWindowsAuthToken="false" startupTimeLimit="3600" />
</system.webServer> </system.webServer>
</configuration> </configuration>

View File

@@ -16,4 +16,4 @@
<DevelopmentServerPort>2018</DevelopmentServerPort> <DevelopmentServerPort>2018</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -56,23 +56,23 @@ namespace ES2015Example
// send the request to the following path or controller action. // send the request to the following path or controller action.
app.UseExceptionHandler("/Home/Error"); app.UseExceptionHandler("/Home/Error");
} }
// Dynamically transpile any .js files under the '/js/' directory // Dynamically transpile any .js files under the '/js/' directory
app.Use(next => async context => { app.Use(next => async context => {
var requestPath = context.Request.Path.Value; var requestPath = context.Request.Path.Value;
if (requestPath.StartsWith("/js/") && requestPath.EndsWith(".js")) { if (requestPath.StartsWith("/js/") && requestPath.EndsWith(".js")) {
var fileInfo = env.WebRootFileProvider.GetFileInfo(requestPath); var fileInfo = env.WebRootFileProvider.GetFileInfo(requestPath);
if (fileInfo.Exists) { if (fileInfo.Exists) {
var transpiled = await nodeServices.Invoke<string>("transpilation.js", fileInfo.PhysicalPath, requestPath); var transpiled = await nodeServices.Invoke<string>("transpilation.js", fileInfo.PhysicalPath, requestPath);
await context.Response.WriteAsync(transpiled); await context.Response.WriteAsync(transpiled);
return; return;
} }
} }
// Not a JS file, or doesn't exist - let some other middleware handle it // Not a JS file, or doesn't exist - let some other middleware handle it
await next.Invoke(context); await next.Invoke(context);
}); });
// Add static files to the request pipeline. // Add static files to the request pipeline.
app.UseStaticFiles(); app.UseStaticFiles();

View File

@@ -1,6 +1,6 @@
Hello Hello
@section scripts { @section scripts {
<script src="lib/system.js"></script> <script src="lib/system.js"></script>
<script>System.import('js/main.js');</script> <script>System.import('js/main.js');</script>
} }

View File

@@ -1,6 +1,6 @@
@{ @{
ViewData["Title"] = "Error"; ViewData["Title"] = "Error";
} }
<h1 class="text-danger">Error.</h1> <h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2> <h2 class="text-danger">An error occurred while processing your request.</h2>

View File

@@ -1,11 +1,11 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>ES2015 Example</title> <title>ES2015 Example</title>
</head> </head>
<body> <body>
@RenderBody() @RenderBody()
@RenderSection("scripts", required: false) @RenderSection("scripts", required: false)
</body> </body>
</html> </html>

View File

@@ -1,2 +1,2 @@
@using ES2015Example @using ES2015Example
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"

View File

@@ -1,3 +1,3 @@
@{ @{
Layout = "_Layout"; Layout = "_Layout";
} }

View File

@@ -40,4 +40,4 @@
"npm install" "npm install"
] ]
} }
} }

View File

@@ -3,7 +3,7 @@ var babelCore = require('babel-core');
module.exports = function(cb, physicalPath, requestPath) { module.exports = function(cb, physicalPath, requestPath) {
var originalContents = fs.readFileSync(physicalPath); var originalContents = fs.readFileSync(physicalPath);
var result = babelCore.transform(originalContents, { var result = babelCore.transform(originalContents, {
sourceMaps: 'inline', sourceMaps: 'inline',
sourceFileName: '/sourcemapped' + requestPath sourceFileName: '/sourcemapped' + requestPath
}); });

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<system.webServer> <system.webServer>
<handlers> <handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" /> <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers> </handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" forwardWindowsAuthToken="false" startupTimeLimit="3600" /> <httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" forwardWindowsAuthToken="false" startupTimeLimit="3600" />
</system.webServer> </system.webServer>
</configuration> </configuration>

View File

@@ -47,7 +47,7 @@ namespace Webpack
} }
app.UseIISPlatformHandler(); app.UseIISPlatformHandler();
if (env.IsDevelopment()) { if (env.IsDevelopment()) {
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {
HotModuleReplacement = true HotModuleReplacement = true

View File

@@ -1,10 +1,10 @@
@{ @{
ViewData["Title"] = "Home Page"; ViewData["Title"] = "Home Page";
} }
<h1>Hello</h1> <h1>Hello</h1>
Hi there. Enter some text: <input /> Hi there. Enter some text: <input />
@section scripts { @section scripts {
<script src="dist/main.js"></script> <script src="dist/main.js"></script>
} }

View File

@@ -1,6 +1,6 @@
@{ @{
ViewData["Title"] = "Error"; ViewData["Title"] = "Error";
} }
<h1 class="text-danger">Error.</h1> <h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2> <h2 class="text-danger">An error occurred while processing your request.</h2>

View File

@@ -1,14 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>@ViewData["Title"]</title> <title>@ViewData["Title"]</title>
<environment names="Production"> <environment names="Production">
<link rel="stylesheet" href="dist/my-styles.css" /> <link rel="stylesheet" href="dist/my-styles.css" />
</environment> </environment>
</head> </head>
<body> <body>
@RenderBody() @RenderBody()
@RenderSection("scripts", required: false) @RenderSection("scripts", required: false)
</body> </body>
</html> </html>

View File

@@ -1,2 +1,2 @@
@using Webpack @using Webpack
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"

View File

@@ -1,3 +1,3 @@
@{ @{
Layout = "_Layout"; Layout = "_Layout";
} }

View File

@@ -14,7 +14,7 @@ module.exports = merge({
], ],
}, },
entry: { entry: {
main: ['./Clientside/App.ts'] main: ['./Clientside/App.ts']
}, },
output: { output: {
path: path.join(__dirname, 'wwwroot', 'dist'), path: path.join(__dirname, 'wwwroot', 'dist'),

View File

@@ -9,7 +9,7 @@ module.exports = {
] ]
}, },
plugins: [ plugins: [
extractLESS, extractLESS,
new webpack.optimize.UglifyJsPlugin({ minimize: true }) new webpack.optimize.UglifyJsPlugin({ minimize: true })
] ]
}; };

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<system.webServer> <system.webServer>
<handlers> <handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/> <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers> </handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false"/> <httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false"/>
</system.webServer> </system.webServer>
</configuration> </configuration>

View File

@@ -27,4 +27,4 @@ namespace MusicStore.Apis
return Json(artists); return Json(artists);
} }
} }
} }

View File

@@ -67,4 +67,4 @@ namespace MusicStore.Apis
return Json(albums); return Json(albums);
} }
} }
} }

View File

@@ -60,4 +60,4 @@ namespace MusicStore.Models
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; } public string ConfirmPassword { get; set; }
} }
} }

View File

@@ -7,7 +7,7 @@ namespace MusicStore.Models
{ {
public Album() public Album()
{ {
// TODO: Temporary hack to populate the orderdetails until EF does this automatically. // TODO: Temporary hack to populate the orderdetails until EF does this automatically.
OrderDetails = new List<OrderDetail>(); OrderDetails = new List<OrderDetail>();
} }
@@ -37,4 +37,4 @@ namespace MusicStore.Models
public virtual ICollection<OrderDetail> OrderDetails { get; set; } public virtual ICollection<OrderDetail> OrderDetails { get; set; }
} }
} }

View File

@@ -9,4 +9,4 @@ namespace MusicStore.Models
[Required] [Required]
public string Name { get; set; } public string Name { get; set; }
} }
} }

View File

@@ -18,4 +18,4 @@ namespace MusicStore.Models
public virtual Album Album { get; set; } public virtual Album Album { get; set; }
} }
} }

View File

@@ -21,4 +21,4 @@ namespace MusicStore.Models
[JsonIgnore] [JsonIgnore]
public virtual ICollection<Album> Albums { get; set; } public virtual ICollection<Album> Albums { get; set; }
} }
} }

View File

@@ -31,4 +31,4 @@ namespace MusicStore.Models
base.OnModelCreating(builder); base.OnModelCreating(builder);
} }
} }
} }

View File

@@ -70,4 +70,4 @@ namespace MusicStore.Models
public ICollection<OrderDetail> OrderDetails { get; set; } public ICollection<OrderDetail> OrderDetails { get; set; }
} }
} }

View File

@@ -11,4 +11,4 @@
public virtual Album Album { get; set; } public virtual Album Album { get; set; }
public virtual Order Order { get; set; } public virtual Order Order { get; set; }
} }
} }

View File

@@ -42,13 +42,13 @@ namespace MusicStore.Models
{ {
// Query in a separate context so that we can attach existing entities as modified // Query in a separate context so that we can attach existing entities as modified
List<TEntity> existingData; List<TEntity> existingData;
using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
using (var db = scope.ServiceProvider.GetService<MusicStoreContext>()) using (var db = scope.ServiceProvider.GetService<MusicStoreContext>())
{ {
existingData = db.Set<TEntity>().ToList(); existingData = db.Set<TEntity>().ToList();
} }
using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
using (var db = scope.ServiceProvider.GetService<MusicStoreContext>()) using (var db = scope.ServiceProvider.GetService<MusicStoreContext>())
{ {
@@ -65,8 +65,8 @@ namespace MusicStore.Models
private static Album[] GetAlbums(string imgUrl, Dictionary<string, Genre> genres, Dictionary<string, Artist> artists) private static Album[] GetAlbums(string imgUrl, Dictionary<string, Genre> genres, Dictionary<string, Artist> artists)
{ {
var albums = new Album[] var albums = new Album[]
{ {
new Album { Title = "The Best Of The Men At Work", Genre = genres["Pop"], Price = 8.99M, Artist = artists["Men At Work"], AlbumArtUrl = imgUrl }, new Album { Title = "The Best Of The Men At Work", Genre = genres["Pop"], Price = 8.99M, Artist = artists["Men At Work"], AlbumArtUrl = imgUrl },
new Album { Title = "...And Justice For All", Genre = genres["Metal"], Price = 8.99M, Artist = artists["Metallica"], AlbumArtUrl = imgUrl }, new Album { Title = "...And Justice For All", Genre = genres["Metal"], Price = 8.99M, Artist = artists["Metallica"], AlbumArtUrl = imgUrl },
new Album { Title = "עד גבול האור", Genre = genres["World"], Price = 8.99M, Artist = artists["אריק אינשטיין"], AlbumArtUrl = imgUrl }, new Album { Title = "עד גבול האור", Genre = genres["World"], Price = 8.99M, Artist = artists["אריק אינשטיין"], AlbumArtUrl = imgUrl },
@@ -912,4 +912,4 @@ namespace MusicStore.Models
} }
} }
} }
} }

View File

@@ -123,7 +123,7 @@ namespace MusicStore.Models
public decimal GetTotal() public decimal GetTotal()
{ {
// Multiply album price by count of that album to get // Multiply album price by count of that album to get
// the current price for each of those albums in the cart // the current price for each of those albums in the cart
// sum all album price totals to get the cart total // sum all album price totals to get the cart total
@@ -190,7 +190,7 @@ namespace MusicStore.Models
if (string.IsNullOrWhiteSpace(sessionCookie)) if (string.IsNullOrWhiteSpace(sessionCookie))
{ {
//A GUID to hold the cartId. //A GUID to hold the cartId.
cartId = Guid.NewGuid().ToString(); cartId = Guid.NewGuid().ToString();
// Send cart Id as a cookie to the client. // Send cart Id as a cookie to the client.
@@ -204,4 +204,4 @@ namespace MusicStore.Models
return cartId; return cartId;
} }
} }
} }

View File

@@ -16,4 +16,4 @@ namespace MusicStore.Infrastructure
base.OnResultExecuting(context); base.OnResultExecuting(context);
} }
} }
} }

View File

@@ -147,4 +147,4 @@ namespace MusicStore.Infrastructure
public int PageSize { get; set; } public int PageSize { get; set; }
} }
} }
} }

View File

@@ -21,7 +21,7 @@ export default function (params: any): Promise<{ html: string }> {
const app = ( const app = (
<Provider store={ store }> <Provider store={ store }>
<RouterContext {...renderProps} /> <RouterContext {...renderProps} />
</Provider> </Provider>
); );
// Perform an initial render that will cause any async tasks (e.g., data access) to begin // Perform an initial render that will cause any async tasks (e.g., data access) to begin

View File

@@ -1,4 +1,4 @@
import * as React from 'react'; import * as React from 'react';
import { Navbar, Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; import { Navbar, Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap';
import { Link } from 'react-router'; import { Link } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap'; import { LinkContainer } from 'react-router-bootstrap';
@@ -25,7 +25,7 @@ class NavMenu extends React.Component<NavMenuProps, void> {
{genres.map(genre => {genres.map(genre =>
<LinkContainer key={ genre.GenreId } to={ `/genre/${ genre.GenreId }` }> <LinkContainer key={ genre.GenreId } to={ `/genre/${ genre.GenreId }` }>
<MenuItem>{ genre.Name }</MenuItem> <MenuItem>{ genre.Name }</MenuItem>
</LinkContainer> </LinkContainer>
)} )}
<MenuItem divider /> <MenuItem divider />
<LinkContainer to={ '/genres' }><MenuItem>More</MenuItem></LinkContainer> <LinkContainer to={ '/genres' }><MenuItem>More</MenuItem></LinkContainer>
@@ -43,7 +43,7 @@ class NavMenu extends React.Component<NavMenuProps, void> {
// Selects which part of global state maps to this component, and defines a type for the resulting props // Selects which part of global state maps to this component, and defines a type for the resulting props
const provider = provide( const provider = provide(
(state: ApplicationState) => state.genreList, (state: ApplicationState) => state.genreList,
GenreList.actionCreators GenreList.actionCreators
); );
type NavMenuProps = typeof provider.allProps; type NavMenuProps = typeof provider.allProps;
export default provider.connect(NavMenu); export default provider.connect(NavMenu);

View File

@@ -22,9 +22,9 @@ class AlbumDetails extends React.Component<AlbumDetailsProps, void> {
const albumData = this.props.album; const albumData = this.props.album;
return <div> return <div>
<h2>{ albumData.Title }</h2> <h2>{ albumData.Title }</h2>
<p><img alt={ albumData.Title } src={ albumData.AlbumArtUrl } /></p> <p><img alt={ albumData.Title } src={ albumData.AlbumArtUrl } /></p>
<div id="album-details"> <div id="album-details">
<p> <p>
<em>Genre:</em> <em>Genre:</em>

View File

@@ -1,4 +1,4 @@
import * as React from 'react'; import * as React from 'react';
import { Link } from 'react-router'; import { Link } from 'react-router';
import { Album } from '../../store/FeaturedAlbums'; import { Album } from '../../store/FeaturedAlbums';

View File

@@ -13,7 +13,7 @@ class GenreDetails extends React.Component<GenreDetailsProps, void> {
componentWillMount() { componentWillMount() {
this.props.requestGenreDetails(parseInt(this.props.params.genreId)); this.props.requestGenreDetails(parseInt(this.props.params.genreId));
} }
componentWillReceiveProps(nextProps: GenreDetailsProps) { componentWillReceiveProps(nextProps: GenreDetailsProps) {
this.props.requestGenreDetails(parseInt(nextProps.params.genreId)); this.props.requestGenreDetails(parseInt(nextProps.params.genreId));
} }

View File

@@ -10,7 +10,7 @@ export default function configureStore(history: HistoryModule.History, initialSt
const reduxRouterMiddleware = syncHistory(history); const reduxRouterMiddleware = syncHistory(history);
const middlewares = [thunk, reduxRouterMiddleware, typedToPlain]; const middlewares = [thunk, reduxRouterMiddleware, typedToPlain];
const devToolsExtension = null;//(window as any).devToolsExtension; // If devTools is installed, connect to it const devToolsExtension = null;//(window as any).devToolsExtension; // If devTools is installed, connect to it
const finalCreateStore = compose( const finalCreateStore = compose(
applyMiddleware(...middlewares), applyMiddleware(...middlewares),
devToolsExtension ? devToolsExtension() : f => f devToolsExtension ? devToolsExtension() : f => f
@@ -20,10 +20,10 @@ export default function configureStore(history: HistoryModule.History, initialSt
const allReducers = buildRootReducer(Store.reducers); const allReducers = buildRootReducer(Store.reducers);
const store = finalCreateStore(allReducers, initialState) as Redux.Store; const store = finalCreateStore(allReducers, initialState) as Redux.Store;
// Required for replaying actions from devtools to work // Required for replaying actions from devtools to work
reduxRouterMiddleware.listenForReplays(store); reduxRouterMiddleware.listenForReplays(store);
// Enable Webpack hot module replacement for reducers // Enable Webpack hot module replacement for reducers
if (module.hot) { if (module.hot) {
module.hot.accept('./store', () => { module.hot.accept('./store', () => {

View File

@@ -47,7 +47,7 @@ class ReceiveAlbumDetails extends Action {
// ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition. // ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition.
// They don't directly mutate state, but they can have external side-effects (such as loading data). // They don't directly mutate state, but they can have external side-effects (such as loading data).
export const actionCreators = { export const actionCreators = {
requestAlbumDetails: (albumId: number): ActionCreator => (dispatch, getState) => { requestAlbumDetails: (albumId: number): ActionCreator => (dispatch, getState) => {
// Only load if it's not already loaded (or currently being loaded) // Only load if it's not already loaded (or currently being loaded)
if (albumId !== getState().albumDetails.requestedAlbumId) { if (albumId !== getState().albumDetails.requestedAlbumId) {
@@ -59,7 +59,7 @@ export const actionCreators = {
dispatch(new ReceiveAlbumDetails(album)); dispatch(new ReceiveAlbumDetails(album));
} }
}); });
dispatch(new RequestAlbumDetails(albumId)); dispatch(new RequestAlbumDetails(albumId));
} }
} }

View File

@@ -42,7 +42,7 @@ export const actionCreators = {
fetch('/api/albums/mostPopular') fetch('/api/albums/mostPopular')
.then(results => results.json()) .then(results => results.json())
.then(albums => dispatch(new ReceiveFeaturedAlbums(albums))); .then(albums => dispatch(new ReceiveFeaturedAlbums(albums)));
return dispatch(new RequestFeaturedAlbums()); return dispatch(new RequestFeaturedAlbums());
} }
} }

View File

@@ -35,7 +35,7 @@ class ReceiveGenreDetails extends Action {
// ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition. // ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition.
// They don't directly mutate state, but they can have external side-effects (such as loading data). // They don't directly mutate state, but they can have external side-effects (such as loading data).
export const actionCreators = { export const actionCreators = {
requestGenreDetails: (genreId: number): ActionCreator => (dispatch, getState) => { requestGenreDetails: (genreId: number): ActionCreator => (dispatch, getState) => {
// Only load if it's not already loaded (or currently being loaded) // Only load if it's not already loaded (or currently being loaded)
if (genreId !== getState().genreDetails.requestedGenreId) { if (genreId !== getState().genreDetails.requestedGenreId) {
@@ -44,10 +44,10 @@ export const actionCreators = {
.then(albums => { .then(albums => {
// Only replace state if it's still the most recent request // Only replace state if it's still the most recent request
if (genreId === getState().genreDetails.requestedGenreId) { if (genreId === getState().genreDetails.requestedGenreId) {
dispatch(new ReceiveGenreDetails(genreId, albums)); dispatch(new ReceiveGenreDetails(genreId, albums));
} }
}); });
dispatch(new RequestGenreDetails(genreId)); dispatch(new RequestGenreDetails(genreId));
} }
} }

View File

@@ -31,7 +31,7 @@ class ReceiveGenresList extends Action {
// ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition. // ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition.
// They don't directly mutate state, but they can have external side-effects (such as loading data). // They don't directly mutate state, but they can have external side-effects (such as loading data).
export const actionCreators = { export const actionCreators = {
requestGenresList: (): ActionCreator => (dispatch, getState) => { requestGenresList: (): ActionCreator => (dispatch, getState) => {
if (!getState().genreList.isLoaded) { if (!getState().genreList.isLoaded) {
fetch('/api/genres') fetch('/api/genres')

View File

@@ -23,5 +23,5 @@ export const reducers = {
}; };
// This type can be used as a hint on action creators so that its 'dispatch' and 'getState' params are // This type can be used as a hint on action creators so that its 'dispatch' and 'getState' params are
// correctly typed to match your store. // correctly typed to match your store.
export type ActionCreator = ActionCreatorGeneric<ApplicationState>; export type ActionCreator = ActionCreatorGeneric<ApplicationState>;

View File

@@ -41,7 +41,7 @@ namespace MusicStore
// Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers. // Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers.
// You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json. // You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json.
// services.AddWebApiConventions(); // services.AddWebApiConventions();
// Add EF services to the service container // Add EF services to the service container
services.AddEntityFramework() services.AddEntityFramework()
.AddSqlite() .AddSqlite()
@@ -78,7 +78,7 @@ namespace MusicStore
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ {
loggerFactory.AddConsole(LogLevel.Warning); loggerFactory.AddConsole(LogLevel.Warning);
// Initialize the sample data // Initialize the sample data
SampleData.InitializeMusicStoreDatabaseAsync(app.ApplicationServices).Wait(); SampleData.InitializeMusicStoreDatabaseAsync(app.ApplicationServices).Wait();
@@ -89,7 +89,7 @@ namespace MusicStore
} }
app.UseIISPlatformHandler(); app.UseIISPlatformHandler();
// In dev mode, the JS/TS/etc is compiled and served dynamically and supports hot replacement. // In dev mode, the JS/TS/etc is compiled and served dynamically and supports hot replacement.
// In production, we assume you've used webpack to emit the prebuilt content to disk. // In production, we assume you've used webpack to emit the prebuilt content to disk.
if (env.IsDevelopment()) { if (env.IsDevelopment()) {
@@ -105,7 +105,7 @@ namespace MusicStore
routes.MapRoute( routes.MapRoute(
name: "default", name: "default",
template: "{controller=Home}/{action=Index}/{id?}"); template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute( routes.MapSpaFallbackRoute(
name: "spa-fallback", name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" }); defaults: new { controller = "Home", action = "Index" });

View File

@@ -1,11 +1,11 @@
@{ @{
ViewData["Title"] = "Home Page"; ViewData["Title"] = "Home Page";
} }
<div id="react-app" asp-prerender-module="ReactApp/boot-server" <div id="react-app" asp-prerender-module="ReactApp/boot-server"
asp-prerender-webpack-config="webpack.config.js"></div> asp-prerender-webpack-config="webpack.config.js"></div>
@section scripts { @section scripts {
<script src="/dist/vendor.bundle.js"></script> <script src="/dist/vendor.bundle.js"></script>
<script src="/dist/main.js"></script> <script src="/dist/main.js"></script>
} }

View File

@@ -1,6 +1,6 @@
@{ @{
ViewData["Title"] = "Error"; ViewData["Title"] = "Error";
} }
<h1 class="text-danger">Error.</h1> <h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2> <h2 class="text-danger">An error occurred while processing your request.</h2>

View File

@@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>@ViewData["Title"]</title> <title>@ViewData["Title"]</title>
<link rel="stylesheet" href="/dist/main.css" /> <link rel="stylesheet" href="/dist/main.css" />
</head> </head>
<body> <body>
@RenderBody() @RenderBody()
@RenderSection("scripts", required: false) @RenderSection("scripts", required: false)
</body> </body>
</html> </html>

View File

@@ -1,3 +1,3 @@
@using MusicStore @using MusicStore
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*, Microsoft.AspNet.SpaServices" @addTagHelper "*, Microsoft.AspNet.SpaServices"

View File

@@ -1,3 +1,3 @@
@{ @{
Layout = "_Layout"; Layout = "_Layout";
} }

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<system.webServer> <system.webServer>
<handlers> <handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/> <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers> </handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false"/> <httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false"/>
</system.webServer> </system.webServer>
</configuration> </configuration>

View File

@@ -16,14 +16,14 @@ namespace ReactExample.Controllers
} }
} }
} }
public class PersonDto { public class PersonDto {
public string name { get; set; } public string name { get; set; }
public string city { get; set; } public string city { get; set; }
public string state { get; set; } public string state { get; set; }
public string country { get; set; } public string country { get; set; }
public string company { get; set; } public string company { get; set; }
[Range(1, 10)] [Range(1, 10)]
public int favoriteNumber { get; set; } public int favoriteNumber { get; set; }
} }

View File

@@ -16,7 +16,7 @@ export default function renderApp (params) {
const app = <RouterContext {...renderProps} />; const app = <RouterContext {...renderProps} />;
// Render it as an HTML string which can be injected into the response // Render it as an HTML string which can be injected into the response
const html = renderToString(app); const html = renderToString(app);
resolve({ html }); resolve({ html });
}); });
}); });

View File

@@ -5,7 +5,7 @@ export class CustomPager extends React.Component {
pageChange(event) { pageChange(event) {
this.props.setPage(parseInt(event.target.getAttribute("data-value"))); this.props.setPage(parseInt(event.target.getAttribute("data-value")));
} }
render() { render() {
var previous = null; var previous = null;
var next = null; var next = null;
@@ -47,4 +47,4 @@ CustomPager.defaultProps = {
nextText: '', nextText: '',
previousText: '', previousText: '',
currentPage: 0 currentPage: 0
}; };

View File

@@ -8,11 +8,11 @@ export class PersonEditor extends React.Component {
super(); super();
this.state = { savedChanges: false }; this.state = { savedChanges: false };
} }
onChange() { onChange() {
this.setState({ savedChanges: false }); this.setState({ savedChanges: false });
} }
submit(model, reset, setErrors) { submit(model, reset, setErrors) {
PersonEditor.sendJson('put', `/api/people/${ this.props.params.personId }`, model).then(response => { PersonEditor.sendJson('put', `/api/people/${ this.props.params.personId }`, model).then(response => {
if (response.ok) { if (response.ok) {
@@ -23,7 +23,7 @@ export class PersonEditor extends React.Component {
} }
}); });
} }
render() { render() {
var personId = parseInt(this.props.params.personId); var personId = parseInt(this.props.params.personId);
var person = fakeData.filter(p => p.id === personId)[0]; var person = fakeData.filter(p => p.id === personId)[0];
@@ -46,12 +46,12 @@ export class PersonEditor extends React.Component {
</Formsy.Form> </Formsy.Form>
</div>; </div>;
} }
static sendJson(method, url, object) { static sendJson(method, url, object) {
return fetch(url, { return fetch(url, {
method: method, method: method,
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(object) body: JSON.stringify(object)
}); });
} }
} }

View File

@@ -6,7 +6,7 @@ import { PersonEditor } from './PersonEditor.jsx';
export const routes = <Route> export const routes = <Route>
<Route path="/" component={ PeopleGrid } /> <Route path="/" component={ PeopleGrid } />
<Route path="/:pageIndex" component={ PeopleGrid } /> <Route path="/:pageIndex" component={ PeopleGrid } />
<Route path="/edit/:personId" component={ PersonEditor } /> <Route path="/edit/:personId" component={ PersonEditor } />
</Route>; </Route>;
export class ReactApp extends React.Component { export class ReactApp extends React.Component {

View File

@@ -16,4 +16,4 @@
<DevelopmentServerPort>2311</DevelopmentServerPort> <DevelopmentServerPort>2311</DevelopmentServerPort>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

Some files were not shown because too many files have changed in this diff Show More