diff --git a/.travis.yml b/.travis.yml
index 9c20b8b..07c15ce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,15 @@
-language: scala
+dist: trusty
sudo: false
+language: java
cache:
directories:
- $HOME/.ivy2
+env:
+ - NODE_VERSION=6
scala:
- 2.11.6
-script:
- - sbt stage
jdk:
- - oraclejdk8
\ No newline at end of file
+ - oraclejdk8
+script:
+ - nvm use $NODE_VERSION
+ - sbt stage -DtsCompileMode=stage
diff --git a/README.md b/README.md
index 28caf96..954e5e3 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,19 @@
Building on top of the fabulous work of @joost-de-vries from [play-angular2-typescript](https://github.com/joost-de-vries/play-angular2-typescript), this project is a Java Angular2 seed.
-#Play Angular2 Typescript sample application [](https://travis-ci.org/joost-de-vries/play-angular2-typescript)
+# Play Angular2 Typescript sample application [](https://travis-ci.org/joost-de-vries/play-angular2-typescript)
This is an activator template that generates a sample Play Angular2 RC4 Typescript 2.0 application.
As mentioned it features an Angular2 application with Typescript compilation integrated with the continuous compilation of Play Scala code. The Typescript code is linted with `tslint`.
-##Installation
+## Installation
Once you have [activator](https://www.typesafe.com/community/core-tools/activator-and-sbt) installed you can run `activator new play-angular2-typescript` and you'll have a local application with a tutorial. Or you can just clone this repo and run `sbt ~run`.
**NB**: Make sure you don't have `typescript` installed globally. If you do have a global npm installation of `typescript` that version will be picked up. And then all bets are off.
A symptom of having an older global `typescript` installation is that you get a `JsTaskFailure` / `TypeError` that the function `convertCompilerOptionsFromJson` can't be found. See [this issue](https://github.com/joost-de-vries/play-angular2-typescript/issues/1)
-##Getting started
+## Getting started
The NG2 application is the standard todomvc app.
This Play project shows 3 ways of loading that app in the browser using Play.
1. let the browser load the typescript files and have them compiled in the browser itself. This is easy to setup. But it makes greater computation demands on the client device. And it is really hard to find out about compilation errors. Which rather defies the added value of typed programming that typescript provides. This is implemented in [this html file](https://github.com/joost-de-vries/play-angular2-typescript/blob/master/app/views/index.scala.html). This template hasn't been ported to Angular RC4 yet.
@@ -24,8 +24,19 @@ For a lot of production applications option 3 will be required. While option 2 i
We can do both without changing our source code by using `sbt ~run` for the former and `sbt stage -DtsCompileMode=stage` for the latter. So to get option 3 to work you'll have to provide that `-DtsCompileMode=stage` jvm argument.
-##what to do if
+## what to do if
"I've created the application through activator and it runs fine in activator but it hangs when I try to run it through sbt"
This is a [known problem](https://github.com/typesafehub/activator/issues/1036) with activator. Activator generates a file `project\play-fork-run.sbt` that causes this. If you remove it or comment out its contents the application will run in sbt.
+## History
+
+### v0.2.0-beta.7
+- upgrades to sbt-typescript 0.3.0-beta.11 and hence typescript 2.3.0
+
+### v0.2.0-beta.6
+- uses tslint 4.0.2
+
+### v0.2.0-beta.5
+- replace todomvc with tour of heroes as demo ng2 application. tx [Isammoc](https://github.com/Isammoc)
+- use 'tslint:reommended' as a basis for tslint rules. Downgrade typescript to a supported version by tslint 3.x
diff --git a/activator.properties b/activator.properties
index 28f24c9..5ce4d81 100644
--- a/activator.properties
+++ b/activator.properties
@@ -1,7 +1,7 @@
name=play-angular2-typescript-java
title=Angular2 Typescript application with Play (Java Version)
description=A Play Angular2 starter application with incremental Typescript compilation.
-tags=playframework,angular2,typescript,java
+tags=playframework,angular,angular2,typescript,java
authorTwitter=detinho_rp
authorLogo=https://avatars0.githubusercontent.com/u/631905?v=3&s=466
authorName=Detinho
diff --git a/app/assets/app/app-routing.module.ts b/app/assets/app/app-routing.module.ts
new file mode 100644
index 0000000..a39f549
--- /dev/null
+++ b/app/assets/app/app-routing.module.ts
@@ -0,0 +1,25 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { DashboardComponent } from './dashboard.component';
+import { HeroesComponent } from './heroes.component';
+import { HeroDetailComponent } from './hero-detail.component';
+
+const routes: Routes = [
+ { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
+ { path: 'dashboard', component: DashboardComponent },
+ { path: 'detail/:id', component: HeroDetailComponent },
+ { path: 'heroes', component: HeroesComponent },
+];
+
+@NgModule({
+ imports: [ RouterModule.forRoot(routes) ],
+ exports: [ RouterModule ],
+})
+export class AppRoutingModule {}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/app.component.css b/app/assets/app/app.component.css
new file mode 100644
index 0000000..6c046fa
--- /dev/null
+++ b/app/assets/app/app.component.css
@@ -0,0 +1,35 @@
+h1 {
+ font-size: 1.2em;
+ color: #999;
+ margin-bottom: 0;
+}
+h2 {
+ font-size: 2em;
+ margin-top: 0;
+ padding-top: 0;
+}
+nav a {
+ padding: 5px 10px;
+ text-decoration: none;
+ margin-top: 10px;
+ display: inline-block;
+ background-color: #eee;
+ border-radius: 4px;
+}
+nav a:visited, a:link {
+ color: #607D8B;
+}
+nav a:hover {
+ color: #039be5;
+ background-color: #CFD8DC;
+}
+nav a.active {
+ color: #039be5;
+}
+
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
\ No newline at end of file
diff --git a/app/assets/app/app.component.ts b/app/assets/app/app.component.ts
new file mode 100644
index 0000000..ecf8371
--- /dev/null
+++ b/app/assets/app/app.component.ts
@@ -0,0 +1,24 @@
+import { Component } from '@angular/core';
+
+@Component({
+// moduleId: module.id,
+ selector: 'my-app',
+ template: `
+
{{title}}
+
+ Dashboard
+ Heroes
+
+
+ `,
+ styleUrls: ['assets/app/app.component.css'],
+})
+export class AppComponent {
+ public title = 'Tour of Heroes';
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/app.html b/app/assets/app/app.html
deleted file mode 100644
index e995d84..0000000
--- a/app/assets/app/app.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
diff --git a/app/assets/app/app.module.ts b/app/assets/app/app.module.ts
index 3cc0f5c..70ab63a 100644
--- a/app/assets/app/app.module.ts
+++ b/app/assets/app/app.module.ts
@@ -1,21 +1,40 @@
-import { NgModule } from "@angular/core"
-import { BrowserModule } from "@angular/platform-browser"
-import { FormsModule } from "@angular/forms"
+import './rxjs-extensions';
-import TodoAppComponent from "./app"
-import { LocalStorageTodoStore } from "./services/store"
-import { TodoStore } from "./services/todo.store"
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { FormsModule } from '@angular/forms';
+import { HttpModule } from '@angular/http';
+
+import { AppRoutingModule } from './app-routing.module';
+
+import { AppComponent } from './app.component';
+import { DashboardComponent } from './dashboard.component';
+import { HeroesComponent } from './heroes.component';
+import { HeroDetailComponent } from './hero-detail.component';
+import { HeroService } from './hero.service';
+import { HeroSearchComponent } from './hero-search.component';
@NgModule({
- imports: [
- BrowserModule
- , FormsModule
- ],
- declarations: [TodoAppComponent],
- bootstrap: [TodoAppComponent],
- providers: [
- {provide: TodoStore, useValue: new LocalStorageTodoStore()}
- ]
+ imports: [
+ BrowserModule,
+ FormsModule,
+ HttpModule,
+ AppRoutingModule,
+ ],
+ declarations: [
+ AppComponent,
+ DashboardComponent,
+ HeroDetailComponent,
+ HeroesComponent,
+ HeroSearchComponent,
+ ],
+ providers: [ HeroService ],
+ bootstrap: [ AppComponent ],
})
-export class TodoAppModule { }
+export class AppModule { }
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/app.ts b/app/assets/app/app.ts
deleted file mode 100644
index c46f9a0..0000000
--- a/app/assets/app/app.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import {Component} from "@angular/core"
-import {Todo} from "./services/store"
-import {TodoStore} from "./services/todo.store"
-
-@Component({
- selector: "todo-app",
- templateUrl: "assets/app/app.html"
-})
-export default class TodoAppComponent {
- newTodoText = ""
-
- constructor(private todoStore:TodoStore) {
- this.todoStore = todoStore
- }
-
- stopEditing(todo:Todo, editedTitle:string) {
- todo.title = editedTitle
- todo.editing = false
- }
-
- cancelEditingTodo(todo:Todo) {
- todo.editing = false
- }
-
- updateEditingTodo(todo:Todo, editedTitle:string) {
- editedTitle = editedTitle.trim()
- todo.editing = false
-
- if (editedTitle.length === 0) {
- return this.todoStore.remove(todo)
- }
-
- todo.title = editedTitle
- }
-
- editTodo(todo:Todo) {
- todo.editing = true
- }
-
- removeCompleted() {
- this.todoStore.removeCompleted()
- }
-
- toggleCompletion(todo:Todo) {
- this.todoStore.toggleCompletion(todo)
- }
-
- remove(todo:Todo) {
- this.todoStore.remove(todo)
- }
-
- addTodo() {
- if (this.newTodoText.trim().length) {
- this.todoStore.add(this.newTodoText)
- this.newTodoText = ""
- }
- }
-}
diff --git a/app/assets/app/dashboard.component.css b/app/assets/app/dashboard.component.css
new file mode 100644
index 0000000..9b3226a
--- /dev/null
+++ b/app/assets/app/dashboard.component.css
@@ -0,0 +1,68 @@
+[class*='col-'] {
+ float: left;
+ padding-right: 20px;
+ padding-bottom: 20px;
+}
+[class*='col-']:last-of-type {
+ padding-right: 0;
+}
+a {
+ text-decoration: none;
+}
+*, *:after, *:before {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+h3 {
+ text-align: center; margin-bottom: 0;
+}
+h4 {
+ position: relative;
+}
+.grid {
+ margin: 0;
+}
+.col-1-4 {
+ width: 25%;
+}
+.module {
+ padding: 20px;
+ text-align: center;
+ color: #eee;
+ max-height: 120px;
+ min-width: 120px;
+ background-color: #607D8B;
+ border-radius: 2px;
+}
+.module:hover {
+ background-color: #EEE;
+ cursor: pointer;
+ color: #607d8b;
+}
+.grid-pad {
+ padding: 10px 0;
+}
+.grid-pad > [class*='col-']:last-of-type {
+ padding-right: 20px;
+}
+@media (max-width: 600px) {
+ .module {
+ font-size: 10px;
+ max-height: 75px; }
+}
+@media (max-width: 1024px) {
+ .grid {
+ margin: 0;
+ }
+ .module {
+ min-width: 60px;
+ }
+}
+
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
\ No newline at end of file
diff --git a/app/assets/app/dashboard.component.html b/app/assets/app/dashboard.component.html
new file mode 100644
index 0000000..2d9fb5b
--- /dev/null
+++ b/app/assets/app/dashboard.component.html
@@ -0,0 +1,16 @@
+Top Heroes
+
+
+
+
+
\ No newline at end of file
diff --git a/app/assets/app/dashboard.component.ts b/app/assets/app/dashboard.component.ts
new file mode 100644
index 0000000..ba6b04c
--- /dev/null
+++ b/app/assets/app/dashboard.component.ts
@@ -0,0 +1,27 @@
+import { Component, OnInit } from '@angular/core';
+
+import { Hero } from './hero';
+import { HeroService } from './hero.service';
+
+@Component({
+// moduleId: module.id,
+ selector: 'my-dashboard',
+ templateUrl: 'assets/app/dashboard.component.html',
+ styleUrls: [ 'assets/app/dashboard.component.css' ],
+})
+export class DashboardComponent implements OnInit {
+ public heroes: Hero[] = [];
+
+ constructor(private heroService: HeroService) { }
+
+ public ngOnInit(): void {
+ this.heroService.getHeroes()
+ .then(heroes => this.heroes = heroes.slice(1, 5));
+ }
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/hero-detail.component.css b/app/assets/app/hero-detail.component.css
new file mode 100644
index 0000000..2a0e285
--- /dev/null
+++ b/app/assets/app/hero-detail.component.css
@@ -0,0 +1,36 @@
+label {
+ display: inline-block;
+ width: 3em;
+ margin: .5em 0;
+ color: #607D8B;
+ font-weight: bold;
+}
+input {
+ height: 2em;
+ font-size: 1em;
+ padding-left: .4em;
+}
+button {
+ margin-top: 20px;
+ font-family: Arial;
+ background-color: #eee;
+ border: none;
+ padding: 5px 10px;
+ border-radius: 4px;
+ cursor: pointer; cursor: hand;
+}
+button:hover {
+ background-color: #cfd8dc;
+}
+button:disabled {
+ background-color: #eee;
+ color: #ccc;
+ cursor: auto;
+}
+
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
\ No newline at end of file
diff --git a/app/assets/app/hero-detail.component.html b/app/assets/app/hero-detail.component.html
new file mode 100644
index 0000000..b700346
--- /dev/null
+++ b/app/assets/app/hero-detail.component.html
@@ -0,0 +1,18 @@
+
+
{{hero.name}} details!
+
+ id: {{hero.id}}
+
+ name:
+
+
+
Back
+
Save
+
+
+
+
\ No newline at end of file
diff --git a/app/assets/app/hero-detail.component.ts b/app/assets/app/hero-detail.component.ts
new file mode 100644
index 0000000..93982e3
--- /dev/null
+++ b/app/assets/app/hero-detail.component.ts
@@ -0,0 +1,44 @@
+import 'rxjs/add/operator/switchMap';
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, Params } from '@angular/router';
+import { Location } from '@angular/common';
+
+import { Hero } from './hero';
+import { HeroService } from './hero.service';
+
+@Component({
+// moduleId: module.id,
+ selector: 'my-hero-detail',
+ templateUrl: 'assets/app/hero-detail.component.html',
+ styleUrls: [ 'assets/app/hero-detail.component.css' ],
+})
+export class HeroDetailComponent implements OnInit {
+ public hero: Hero;
+
+ constructor(
+ private heroService: HeroService,
+ private route: ActivatedRoute,
+ private location: Location,
+ ) {}
+
+ public ngOnInit(): void {
+ this.route.params // tslint:disable-next-line:no-string-literal
+ .switchMap((params: Params) => this.heroService.getHero(+params['id']))
+ .subscribe(hero => this.hero = hero);
+ }
+
+ public save(): void {
+ this.heroService.update(this.hero)
+ .then(() => this.goBack());
+ }
+
+ public goBack(): void {
+ this.location.back();
+ }
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/hero-search.component.css b/app/assets/app/hero-search.component.css
new file mode 100644
index 0000000..462d233
--- /dev/null
+++ b/app/assets/app/hero-search.component.css
@@ -0,0 +1,22 @@
+.search-result{
+ border-bottom: 1px solid gray;
+ border-left: 1px solid gray;
+ border-right: 1px solid gray;
+ width:195px;
+ height: 20px;
+ padding: 5px;
+ background-color: white;
+ cursor: pointer;
+}
+
+#search-box{
+ width: 200px;
+ height: 20px;
+}
+
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
\ No newline at end of file
diff --git a/app/assets/app/hero-search.component.html b/app/assets/app/hero-search.component.html
new file mode 100644
index 0000000..64c6ceb
--- /dev/null
+++ b/app/assets/app/hero-search.component.html
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/assets/app/hero-search.component.ts b/app/assets/app/hero-search.component.ts
new file mode 100644
index 0000000..6c33fd6
--- /dev/null
+++ b/app/assets/app/hero-search.component.ts
@@ -0,0 +1,55 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { Observable } from 'rxjs/Observable';
+import { Subject } from 'rxjs/Subject';
+
+import { HeroSearchService } from './hero-search.service';
+import { Hero } from './hero';
+
+@Component({
+// moduleId: module.id,
+ selector: 'hero-search',
+ templateUrl: 'assets/app/hero-search.component.html',
+ styleUrls: [ 'assets/app/hero-search.component.css' ],
+ providers: [HeroSearchService],
+})
+export class HeroSearchComponent implements OnInit {
+ public heroes: Observable;
+ private searchTerms = new Subject();
+
+ constructor(
+ private heroSearchService: HeroSearchService,
+ private router: Router) {}
+
+ // Push a search term into the observable stream.
+ public search(term: string): void {
+ this.searchTerms.next(term);
+ }
+
+ public ngOnInit(): void {
+ this.heroes = this.searchTerms
+ .debounceTime(300) // wait for 300ms pause in events
+ .distinctUntilChanged() // ignore if next search term is same as previous
+ .switchMap(term => term // switch to new observable each time
+ // return the http search observable
+ ? this.heroSearchService.search(term)
+ // or the observable of empty heroes if no search term
+ : Observable.of([]))
+ .catch(error => {
+ // TODO: real error handling
+// console.log(error);
+ return Observable.of([]);
+ });
+ }
+
+ public gotoDetail(hero: Hero): void {
+ const link = ['/detail', hero.id];
+ this.router.navigate(link);
+ }
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/hero-search.service.ts b/app/assets/app/hero-search.service.ts
new file mode 100644
index 0000000..9d11036
--- /dev/null
+++ b/app/assets/app/hero-search.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core';
+import { Http, Response } from '@angular/http';
+import { Observable } from 'rxjs';
+
+import { Hero } from './hero';
+
+@Injectable()
+export class HeroSearchService {
+
+ constructor(private http: Http) {}
+
+ public search(term: string): Observable {
+ return this.http
+ .get(`app/heroes/?name=${term}`)
+ .map((r: Response) => r.json().data as Hero[]);
+ }
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/hero.service.ts b/app/assets/app/hero.service.ts
new file mode 100644
index 0000000..c1c30eb
--- /dev/null
+++ b/app/assets/app/hero.service.ts
@@ -0,0 +1,63 @@
+import { Injectable } from '@angular/core';
+import { Headers, Http } from '@angular/http';
+
+import 'rxjs/add/operator/toPromise';
+
+import { Hero } from './hero';
+
+@Injectable()
+export class HeroService {
+
+ private headers = new Headers({'Content-Type': 'application/json'});
+ private heroesUrl = 'api/heroes';
+
+ constructor(private http: Http) { }
+
+ public getHeroes(): Promise {
+ return this.http.get(this.heroesUrl)
+ .toPromise()
+ .then(response => response.json().data as Hero[])
+ .catch(this.handleError);
+ }
+
+ public getHero(id: number): Promise {
+ return this.getHeroes()
+ .then(heroes => heroes.find(hero => hero.id === id));
+ }
+
+ public delete(id: number): Promise {
+ const url = `${this.heroesUrl}/${id}`;
+ return this.http.delete(url, {headers: this.headers})
+ .toPromise()
+ .then(() => null)
+ .catch(this.handleError);
+ }
+
+ public create(name: string): Promise {
+ return this.http
+ .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers})
+ .toPromise()
+ .then(res => res.json().data)
+ .catch(this.handleError);
+ }
+
+ public update(hero: Hero): Promise {
+ const url = `${this.heroesUrl}/${hero.id}`;
+ return this.http
+ .put(url, JSON.stringify(hero), {headers: this.headers})
+ .toPromise()
+ .then(() => hero)
+ .catch(this.handleError);
+ }
+
+ private handleError(error: any): Promise {
+// console.error('An error occurred', error); // for demo purposes only
+ return Promise.reject(error.message || error);
+ }
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/hero.ts b/app/assets/app/hero.ts
new file mode 100644
index 0000000..f518f22
--- /dev/null
+++ b/app/assets/app/hero.ts
@@ -0,0 +1,10 @@
+export class Hero {
+ public id: number;
+ public name: string;
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/heroes.component.css b/app/assets/app/heroes.component.css
new file mode 100644
index 0000000..a1aba0e
--- /dev/null
+++ b/app/assets/app/heroes.component.css
@@ -0,0 +1,73 @@
+.selected {
+ background-color: #CFD8DC !important;
+ color: white;
+}
+.heroes {
+ margin: 0 0 2em 0;
+ list-style-type: none;
+ padding: 0;
+ width: 15em;
+}
+.heroes li {
+ cursor: pointer;
+ position: relative;
+ left: 0;
+ background-color: #EEE;
+ margin: .5em;
+ padding: .3em 0;
+ height: 1.6em;
+ border-radius: 4px;
+}
+.heroes li:hover {
+ color: #607D8B;
+ background-color: #DDD;
+ left: .1em;
+}
+.heroes li.selected:hover {
+ background-color: #BBD8DC !important;
+ color: white;
+}
+.heroes .text {
+ position: relative;
+ top: -3px;
+}
+.heroes .badge {
+ display: inline-block;
+ font-size: small;
+ color: white;
+ padding: 0.8em 0.7em 0 0.7em;
+ background-color: #607D8B;
+ line-height: 1em;
+ position: relative;
+ left: -1px;
+ top: -4px;
+ height: 1.8em;
+ margin-right: .8em;
+ border-radius: 4px 0 0 4px;
+}
+button {
+ font-family: Arial;
+ background-color: #eee;
+ border: none;
+ padding: 5px 10px;
+ border-radius: 4px;
+ cursor: pointer;
+ cursor: hand;
+}
+button:hover {
+ background-color: #cfd8dc;
+}
+button.delete {
+ float:right;
+ margin-top: 2px;
+ margin-right: .8em;
+ background-color: gray !important;
+ color:white;
+}
+
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
\ No newline at end of file
diff --git a/app/assets/app/heroes.component.html b/app/assets/app/heroes.component.html
new file mode 100644
index 0000000..c90ffb4
--- /dev/null
+++ b/app/assets/app/heroes.component.html
@@ -0,0 +1,29 @@
+My Heroes
+
+ Hero name:
+
+ Add
+
+
+
+
+ {{hero.id}}
+ {{hero.name}}
+ x
+
+
+
+
+ {{selectedHero.name | uppercase}} is my hero
+
+ View Details
+
+
+
+
\ No newline at end of file
diff --git a/app/assets/app/heroes.component.ts b/app/assets/app/heroes.component.ts
new file mode 100644
index 0000000..eb785d0
--- /dev/null
+++ b/app/assets/app/heroes.component.ts
@@ -0,0 +1,63 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+
+import { Hero } from './hero';
+import { HeroService } from './hero.service';
+
+@Component({
+// moduleId: module.id,
+ selector: 'my-heroes',
+ templateUrl: 'assets/app/heroes.component.html',
+ styleUrls: [ 'assets/app/heroes.component.css' ],
+})
+export class HeroesComponent implements OnInit {
+ public heroes: Hero[];
+ public selectedHero: Hero;
+
+ constructor(
+ private heroService: HeroService,
+ private router: Router) { }
+
+ public add(name: string): void {
+ name = name.trim();
+ if (!name) { return; }
+ this.heroService.create(name)
+ .then(hero => {
+ this.heroes.push(hero);
+ this.selectedHero = null;
+ });
+ }
+
+ public delete(hero: Hero): void {
+ this.heroService
+ .delete(hero.id)
+ .then(() => {
+ this.heroes = this.heroes.filter(h => h !== hero);
+ if (this.selectedHero === hero) { this.selectedHero = null; }
+ });
+ }
+
+ public ngOnInit(): void {
+ this.getHeroes();
+ }
+
+ public onSelect(hero: Hero): void {
+ this.selectedHero = hero;
+ }
+
+ public gotoDetail(): void {
+ this.router.navigate(['/detail', this.selectedHero.id]);
+ }
+
+ private getHeroes(): void {
+ this.heroService
+ .getHeroes()
+ .then(heroes => this.heroes = heroes);
+ }
+}
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/main.ts b/app/assets/app/main.ts
index a6df449..1347c80 100644
--- a/app/assets/app/main.ts
+++ b/app/assets/app/main.ts
@@ -1,4 +1,5 @@
-import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"
-import { TodoAppModule } from "./app.module"
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
-platformBrowserDynamic().bootstrapModule(TodoAppModule)
+const platform = platformBrowserDynamic();
+platform.bootstrapModule(AppModule);
diff --git a/app/assets/app/rxjs-extensions.ts b/app/assets/app/rxjs-extensions.ts
new file mode 100644
index 0000000..4c3e2b9
--- /dev/null
+++ b/app/assets/app/rxjs-extensions.ts
@@ -0,0 +1,18 @@
+// Observable class extensions
+import 'rxjs/add/observable/of';
+import 'rxjs/add/observable/throw';
+
+// Observable operators
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/debounceTime';
+import 'rxjs/add/operator/distinctUntilChanged';
+import 'rxjs/add/operator/do';
+import 'rxjs/add/operator/filter';
+import 'rxjs/add/operator/map';
+import 'rxjs/add/operator/switchMap';
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
diff --git a/app/assets/app/services/store.ts b/app/assets/app/services/store.ts
deleted file mode 100644
index 928ae9c..0000000
--- a/app/assets/app/services/store.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import {Injectable} from "@angular/core"
-import {TodoStore} from "./todo.store"
-
-export interface Todo {
- completed: Boolean
- editing: Boolean
-
- title: String
-}
-@Injectable()
-export class LocalStorageTodoStore implements TodoStore {
- todos:Array
-
- constructor() {
- this.todos = JSON.parse(localStorage.getItem("angular2-todos") || "[]")
- }
-
- private updateStore() {
- localStorage.setItem("angular2-todos", JSON.stringify(this.todos))
- }
-
- private getWithCompleted(completed:Boolean) {
- return this.todos.filter((todo:Todo) => todo.completed === completed)
- }
-
- allCompleted() {
- return this.todos.length === this.getCompleted().length
- }
-
- setAllTo(completed:Boolean) {
- this.todos.forEach((t:Todo) => t.completed = completed)
- this.updateStore()
- }
-
- removeCompleted() {
- this.todos = this.getWithCompleted(false)
- this.updateStore()
- }
-
- getRemaining() {
- return this.getWithCompleted(false)
- }
-
- getCompleted() {
- return this.getWithCompleted(true)
- }
-
- toggleCompletion(todo:Todo) {
- todo.completed = !todo.completed
- this.updateStore()
- }
-
- remove(todo:Todo) {
- this.todos.splice(this.todos.indexOf(todo), 1)
- this.updateStore()
- }
-
- add(title:String) {
- const todo = {
- completed: false,
- editing: false,
- title: title
- }
- this.todos.push(todo)
- this.updateStore()
- }
-}
diff --git a/app/assets/app/services/todo.store.ts b/app/assets/app/services/todo.store.ts
deleted file mode 100644
index 999c74b..0000000
--- a/app/assets/app/services/todo.store.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import {Todo} from "./store"
-
-export abstract class TodoStore {
-
- abstract allCompleted():boolean
-
- abstract setAllTo(completed:Boolean):void
-
- abstract removeCompleted():void
-
- abstract getRemaining():Array
-
- abstract getCompleted():Array
-
- abstract toggleCompletion(todo:Todo):void
-
- abstract remove(todo:Todo):void
-
- abstract add(title:String):void
-}
diff --git a/app/controllers/Application.java b/app/controllers/Application.java
index 349dea3..8ff7302 100644
--- a/app/controllers/Application.java
+++ b/app/controllers/Application.java
@@ -15,4 +15,12 @@ public Result index() {
return ok(index1.render());
}
+ public Result apiNotFound(String notFound) {
+ return notFound(notFound);
+ }
+
+ public Result other(String other) {
+ return index();
+ }
+
}
diff --git a/app/controllers/Heroes.java b/app/controllers/Heroes.java
new file mode 100644
index 0000000..5d81726
--- /dev/null
+++ b/app/controllers/Heroes.java
@@ -0,0 +1,56 @@
+package controllers;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.POJONode;
+import com.google.inject.Inject;
+import play.mvc.Result;
+import services.HeroesService;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+
+import static play.mvc.Controller.request;
+import static play.mvc.Results.badRequest;
+import static play.mvc.Results.ok;
+
+
+public class Heroes {
+ @Inject
+ private HeroesService heroesService;
+
+ public CompletionStage all() {
+ return heroesService.all().thenApply((List heroes) -> ok(toDataField(heroes)));
+ }
+
+ private JsonNode toDataField(Object value) {
+ ObjectNode jsonNodes = JsonNodeFactory.instance.objectNode();
+ jsonNodes.set("data", new POJONode(value));
+ return jsonNodes;
+ }
+
+ public CompletionStage delete(int id) {
+ return heroesService.delete(id).thenApply((Optional hero) -> ok(""));
+ }
+
+ public CompletionStage create() {
+ final String name = request().body().asJson().get("name").textValue();
+ if (name != null) {
+ return heroesService.create(name).thenApply((HeroesService.Hero hero) -> ok(toDataField(hero)));
+ } else {
+ return CompletableFuture.completedFuture(badRequest("expected 'name'"));
+ }
+ }
+
+ public CompletionStage update(int id) {
+ final String name = request().body().asJson().get("name").textValue();
+ if (name != null) {
+ return heroesService.update(id, name).thenApply((HeroesService.Hero hero) -> ok(toDataField(hero)));
+ } else {
+ return CompletableFuture.completedFuture(badRequest("expected 'name'"));
+ }
+ }
+}
diff --git a/app/services/HeroesService.java b/app/services/HeroesService.java
new file mode 100644
index 0000000..1f56552
--- /dev/null
+++ b/app/services/HeroesService.java
@@ -0,0 +1,77 @@
+package services;
+
+import com.google.inject.Singleton;
+
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.stream.Collectors;
+
+@Singleton
+public class HeroesService {
+
+ private Map heroes = new HashMap() {{
+ put(11, new Hero(11, "Mr. Nice"));
+ put(12, new Hero(12, "Narco"));
+ put(13, new Hero(13, "Bombasto"));
+ put(14, new Hero(14, "Celeritas"));
+ put(15, new Hero(15, "Magneta"));
+ put(16, new Hero(16, "RubberMan"));
+ put(17, new Hero(17, "Dynama"));
+ put(18, new Hero(18, "Dr IQ"));
+ put(19, new Hero(19, "Magma"));
+ put(20, new Hero(20, "Tornado"));
+ }};
+
+ public CompletionStage> all() {
+ return CompletableFuture.supplyAsync(() -> heroes.values().stream().sorted((o1, o2) -> Comparator.comparing((Hero h) -> h.id).compare(o1, o2)).collect(Collectors.toList()));
+ }
+
+ public CompletionStage> delete(int id) {
+ return CompletableFuture.supplyAsync(() -> Optional.ofNullable(heroes.remove(id)));
+ }
+
+ public CompletionStage create(String name) {
+ return CompletableFuture.supplyAsync(() -> {
+ final int nextNewId = heroes.keySet().stream().mapToInt(i -> i).max().getAsInt() + 1;
+ Hero hero = new Hero(nextNewId, name);
+ heroes.put(hero.id, hero);
+ return hero;
+ });
+ }
+
+ public CompletionStage update(int id, String name) {
+ return CompletableFuture.supplyAsync(() -> {
+ Hero hero = new Hero(id, name);
+ heroes.put(hero.id, hero);
+ return hero;
+ });
+ }
+
+
+ public static class Hero {
+ private int id;
+ private String name;
+
+ public Hero(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+}
diff --git a/app/views/index.scala.html b/app/views/index.scala.html
index 4c69a3b..cf5398d 100644
--- a/app/views/index.scala.html
+++ b/app/views/index.scala.html
@@ -3,10 +3,10 @@
@* in this version of the application the typescript compilation is done in the browser *@
+
- Angular2 • TodoMVC
-
-
+ Angular Tour of Heroes
+
@@ -15,16 +15,7 @@
-
-
+ Loading...
@@ -36,6 +36,7 @@
'compiler',
'core',
'forms',
+ 'router',
'http',
'platform-browser',
'platform-browser-dynamic',
@@ -55,7 +56,7 @@
// Add package entries for angular packages
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
- ngPackageNames.forEach(setPackageConfig)
+ ngPackageNames.forEach(setPackageConfig);
// Add map entries for angular packages
ngPackageNames.forEach(function(pkgName){
@@ -64,7 +65,7 @@
System.config({
map : map,
- packages: packages,
+ packages: packages
});
@* SystemJs works out which other modules our app module depends on and will download and load them*@
System.import('app')
@@ -73,14 +74,6 @@
-
-
+ Loading...
diff --git a/app/views/index2.scala.html b/app/views/index2.scala.html
index d1562cc..641212a 100644
--- a/app/views/index2.scala.html
+++ b/app/views/index2.scala.html
@@ -2,10 +2,10 @@
@* this version of the application loads the application as one file. *@
+
- Angular2 • TodoMVC
-
-
+ Angular Tour of Heroes
+
@@ -24,15 +24,6 @@
-
-
+ Loading...
diff --git a/attribution.md b/attribution.md
deleted file mode 100644
index 9c12522..0000000
--- a/attribution.md
+++ /dev/null
@@ -1,4 +0,0 @@
-#Attribution
-
-This activator template uses
-- the [Angular2 Typescript todomvc](https://github.com/tastejs/todomvc/tree/master/examples/angular2)
\ No newline at end of file
diff --git a/build.sbt b/build.sbt
index 46b056f..30f5ff4 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,13 +1,20 @@
name := """play-angular2-typescript-java"""
-version := "0.2.0-beta.4"
+version := "0.2.0-beta.7"
lazy val root = (project in file(".")).enablePlugins(PlayJava)
scalaVersion := "2.11.8"
incOptions := incOptions.value.withNameHashing(true)
updateOptions := updateOptions.value.withCachedResolution(cachedResoluton = true)
+//we use nodejs to make our typescript build as fast as possible
+JsEngineKeys.engineType := JsEngineKeys.EngineType.Node
+
+resolvers ++= Seq(
+ Resolver.jcenterRepo,
+ Resolver.bintrayRepo("webjars","maven")
+)
libraryDependencies ++= {
- val ngVersion="2.0.2"
+ val ngVersion="2.2.0"
Seq(
cache,
@@ -15,24 +22,24 @@ libraryDependencies ++= {
"org.webjars.npm" % "angular__common" % ngVersion,
"org.webjars.npm" % "angular__compiler" % ngVersion,
"org.webjars.npm" % "angular__core" % ngVersion,
+ "org.webjars.npm" % "angular__http" % ngVersion,
"org.webjars.npm" % "angular__forms" % ngVersion,
+ "org.webjars.npm" % "angular__router" % "3.2.0",
"org.webjars.npm" % "angular__platform-browser-dynamic" % ngVersion,
"org.webjars.npm" % "angular__platform-browser" % ngVersion,
- "org.webjars.npm" % "systemjs" % "0.19.39",
- "org.webjars.npm" % "todomvc-common" % "1.0.2",
+ "org.webjars.npm" % "systemjs" % "0.19.40",
"org.webjars.npm" % "rxjs" % "5.0.0-beta.12",
- "org.webjars.npm" % "es6-promise" % "3.1.2",
- "org.webjars.npm" % "es6-shim" % "0.35.1",
"org.webjars.npm" % "reflect-metadata" % "0.1.8",
- "org.webjars.npm" % "zone.js" % "0.6.25",
+ "org.webjars.npm" % "zone.js" % "0.6.26",
"org.webjars.npm" % "core-js" % "2.4.1",
"org.webjars.npm" % "symbol-observable" % "1.0.1",
- "org.webjars.npm" % "typescript" % "2.0.3",
+ "org.webjars.npm" % "typescript" % "2.2.1",
//tslint dependency
- "org.webjars.npm" % "tslint-eslint-rules" % "2.1.0",
- "org.webjars.npm" % "codelyzer" % "0.0.28",
+ "org.webjars.npm" % "tslint-eslint-rules" % "3.4.0",
+ "org.webjars.npm" % "tslint-microsoft-contrib" % "4.0.0",
+ // "org.webjars.npm" % "codelyzer" % "2.0.0-beta.1",
"org.webjars.npm" % "types__jasmine" % "2.2.26-alpha" % "test"
//test
// "org.webjars.npm" % "jasmine-core" % "2.4.1"
@@ -40,17 +47,16 @@ libraryDependencies ++= {
}
dependencyOverrides += "org.webjars.npm" % "minimatch" % "3.0.0"
-// the typescript typing information is by convention in the typings directory
-// It provides ES6 implementations. This is required when compiling to ES5.
-typingsFile := Some(baseDirectory.value / "typings" / "index.d.ts")
-
// use the webjars npm directory (target/web/node_modules ) for resolution of module imports of angular2/core etc
resolveFromWebjarsNodeModulesDir := true
+tsCodesToIgnore := List(canNotFindModule)
+
// use the combined tslint and eslint rules plus ng2 lint rules
(rulesDirectories in tslint) := Some(List(
tslintEslintRulesDir.value,
ng2LintRulesDir.value
))
+logLevel in tslint := Level.Debug
routesGenerator := InjectedRoutesGenerator
diff --git a/conf/routes b/conf/routes
index e71a0bd..5da21b2 100644
--- a/conf/routes
+++ b/conf/routes
@@ -7,3 +7,13 @@ GET / controllers.Application.index
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
+
+GET /api/heroes controllers.Heroes.all
+POST /api/heroes controllers.Heroes.create
+PUT /api/heroes/:id controllers.Heroes.update(id:Int)
+DELETE /api/heroes/:id controllers.Heroes.delete(id:Int)
+
+GET /api/*notFound controllers.Application.apiNotFound(notFound)
+
+# Map 404 to an index bis
+GET /*others controllers.Application.other(others)
diff --git a/project/build.properties b/project/build.properties
index 43b8278..64317fd 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=0.13.11
+sbt.version=0.13.15
diff --git a/project/plugins.sbt b/project/plugins.sbt
index cbfd626..ef5deee 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,13 +1,17 @@
+
// The Play plugin
-addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.3")
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.10")
// provides server side compilation of typescript to ecmascript 5 or 3
-addSbtPlugin("name.de-vries" % "sbt-typescript" % "0.3.0-beta.5")
+addSbtPlugin("name.de-vries" % "sbt-typescript" % "0.3.0-beta.11")
// checks your typescript code for error prone constructions
-addSbtPlugin("name.de-vries" % "sbt-tslint" % "3.13.0")
+addSbtPlugin("name.de-vries" % "sbt-tslint" % "5.1.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.0")
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10")
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2")
+
+//addSbtPlugin("com.typesafe.sbt" % "sbt-js-engine" % "1.1.4")
+//addSbtPlugin("com.typesafe.sbt" % "sbt-web" % "1.4.0")
diff --git a/public/stylesheets/styles.css b/public/stylesheets/styles.css
new file mode 100644
index 0000000..38d492e
--- /dev/null
+++ b/public/stylesheets/styles.css
@@ -0,0 +1,148 @@
+/* Master Styles */
+h1 {
+ color: #369;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 250%;
+}
+h2, h3 {
+ color: #444;
+ font-family: Arial, Helvetica, sans-serif;
+ font-weight: lighter;
+}
+body {
+ margin: 2em;
+}
+body, input[text], button {
+ color: #888;
+ font-family: Cambria, Georgia;
+}
+a {
+ cursor: pointer;
+ cursor: hand;
+}
+button {
+ font-family: Arial;
+ background-color: #eee;
+ border: none;
+ padding: 5px 10px;
+ border-radius: 4px;
+ cursor: pointer;
+ cursor: hand;
+}
+button:hover {
+ background-color: #cfd8dc;
+}
+button:disabled {
+ background-color: #eee;
+ color: #aaa;
+ cursor: auto;
+}
+
+/* Navigation link styles */
+nav a {
+ padding: 5px 10px;
+ text-decoration: none;
+ margin-top: 10px;
+ display: inline-block;
+ background-color: #eee;
+ border-radius: 4px;
+}
+nav a:visited, a:link {
+ color: #607D8B;
+}
+nav a:hover {
+ color: #039be5;
+ background-color: #CFD8DC;
+}
+nav a.active {
+ color: #039be5;
+}
+
+/* items class */
+.items {
+ margin: 0 0 2em 0;
+ list-style-type: none;
+ padding: 0;
+ width: 24em;
+}
+.items li {
+ cursor: pointer;
+ position: relative;
+ left: 0;
+ background-color: #EEE;
+ margin: .5em;
+ padding: .3em 0;
+ height: 1.6em;
+ border-radius: 4px;
+}
+.items li:hover {
+ color: #607D8B;
+ background-color: #DDD;
+ left: .1em;
+}
+.items li.selected:hover {
+ background-color: #BBD8DC;
+ color: white;
+}
+.items .text {
+ position: relative;
+ top: -3px;
+}
+.items {
+ margin: 0 0 2em 0;
+ list-style-type: none;
+ padding: 0;
+ width: 24em;
+}
+.items li {
+ cursor: pointer;
+ position: relative;
+ left: 0;
+ background-color: #EEE;
+ margin: .5em;
+ padding: .3em 0;
+ height: 1.6em;
+ border-radius: 4px;
+}
+.items li:hover {
+ color: #607D8B;
+ background-color: #DDD;
+ left: .1em;
+}
+.items li.selected {
+ background-color: #CFD8DC;
+ color: white;
+}
+
+.items li.selected:hover {
+ background-color: #BBD8DC;
+}
+.items .text {
+ position: relative;
+ top: -3px;
+}
+.items .badge {
+ display: inline-block;
+ font-size: small;
+ color: white;
+ padding: 0.8em 0.7em 0 0.7em;
+ background-color: #607D8B;
+ line-height: 1em;
+ position: relative;
+ left: -1px;
+ top: -4px;
+ height: 1.8em;
+ margin-right: .8em;
+ border-radius: 4px 0 0 4px;
+}
+/* everywhere else */
+* {
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+
+/*
+Copyright 2016 Google Inc. All Rights Reserved.
+Use of this source code is governed by an MIT-style license that
+can be found in the LICENSE file at http://angular.io/license
+*/
\ No newline at end of file
diff --git a/public/stylesheets/todomvc-app.css b/public/stylesheets/todomvc-app.css
deleted file mode 100644
index de37a5b..0000000
--- a/public/stylesheets/todomvc-app.css
+++ /dev/null
@@ -1,374 +0,0 @@
-html,
-body {
- margin: 0;
- padding: 0;
-}
-
-button {
- margin: 0;
- padding: 0;
- border: 0;
- background: none;
- font-size: 100%;
- vertical-align: baseline;
- font-family: inherit;
- font-weight: inherit;
- color: inherit;
- -webkit-appearance: none;
- appearance: none;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-body {
- font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
- line-height: 1.4em;
- background: #f5f5f5;
- color: #4d4d4d;
- min-width: 230px;
- max-width: 550px;
- margin: 0 auto;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- font-weight: 300;
-}
-
-button,
-input[type="checkbox"] {
- outline: none;
-}
-
-.hidden {
- display: none;
-}
-
-.todoapp {
- background: #fff;
- margin: 130px 0 40px 0;
- position: relative;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
- 0 25px 50px 0 rgba(0, 0, 0, 0.1);
-}
-
-.todoapp input::-webkit-input-placeholder {
- font-style: italic;
- font-weight: 300;
- color: #e6e6e6;
-}
-
-.todoapp input::-moz-placeholder {
- font-style: italic;
- font-weight: 300;
- color: #e6e6e6;
-}
-
-.todoapp input::input-placeholder {
- font-style: italic;
- font-weight: 300;
- color: #e6e6e6;
-}
-
-.todoapp h1 {
- position: absolute;
- top: -155px;
- width: 100%;
- font-size: 100px;
- font-weight: 100;
- text-align: center;
- color: rgba(175, 47, 47, 0.15);
- -webkit-text-rendering: optimizeLegibility;
- -moz-text-rendering: optimizeLegibility;
- text-rendering: optimizeLegibility;
-}
-
-.new-todo,
-.edit {
- position: relative;
- margin: 0;
- width: 100%;
- font-size: 24px;
- font-family: inherit;
- font-weight: inherit;
- line-height: 1.4em;
- border: 0;
- outline: none;
- color: inherit;
- padding: 6px;
- border: 1px solid #999;
- box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
- box-sizing: border-box;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-.new-todo {
- padding: 16px 16px 16px 60px;
- border: none;
- background: rgba(0, 0, 0, 0.003);
- box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
-}
-
-.main {
- position: relative;
- z-index: 2;
- border-top: 1px solid #e6e6e6;
-}
-
-label[for='toggle-all'] {
- display: none;
-}
-
-.toggle-all {
- position: absolute;
- top: -55px;
- left: -12px;
- width: 60px;
- height: 34px;
- text-align: center;
- border: none; /* Mobile Safari */
-}
-
-.toggle-all:before {
- content: '❯';
- font-size: 22px;
- color: #e6e6e6;
- padding: 10px 27px 10px 27px;
-}
-
-.toggle-all:checked:before {
- color: #737373;
-}
-
-.todo-list {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.todo-list li {
- position: relative;
- font-size: 24px;
- border-bottom: 1px solid #ededed;
-}
-
-.todo-list li:last-child {
- border-bottom: none;
-}
-
-.todo-list li.editing {
- border-bottom: none;
- padding: 0;
-}
-
-.todo-list li.editing .edit {
- display: block;
- width: 506px;
- padding: 13px 17px 12px 17px;
- margin: 0 0 0 43px;
-}
-
-.todo-list li.editing .view {
- display: none;
-}
-
-.todo-list li .toggle {
- text-align: center;
- width: 40px;
- /* auto, since non-WebKit browsers doesn't support input styling */
- height: auto;
- position: absolute;
- top: 0;
- bottom: 0;
- margin: auto 0;
- border: none; /* Mobile Safari */
- -webkit-appearance: none;
- appearance: none;
-}
-
-.todo-list li .toggle:after {
- content: url('data:image/svg+xml;utf8, ');
-}
-
-.todo-list li .toggle:checked:after {
- content: url('data:image/svg+xml;utf8, ');
-}
-
-.todo-list li label {
- white-space: pre-line;
- word-break: break-all;
- padding: 15px 60px 15px 15px;
- margin-left: 45px;
- display: block;
- line-height: 1.2;
- transition: color 0.4s;
-}
-
-.todo-list li.completed label {
- color: #d9d9d9;
- text-decoration: line-through;
-}
-
-.todo-list li .destroy {
- display: none;
- position: absolute;
- top: 0;
- right: 10px;
- bottom: 0;
- width: 40px;
- height: 40px;
- margin: auto 0;
- font-size: 30px;
- color: #cc9a9a;
- margin-bottom: 11px;
- transition: color 0.2s ease-out;
-}
-
-.todo-list li .destroy:hover {
- color: #af5b5e;
-}
-
-.todo-list li .destroy:after {
- content: '×';
-}
-
-.todo-list li:hover .destroy {
- display: block;
-}
-
-.todo-list li .edit {
- display: none;
-}
-
-.todo-list li.editing:last-child {
- margin-bottom: -1px;
-}
-
-.footer {
- color: #777;
- padding: 10px 15px;
- height: 20px;
- text-align: center;
- border-top: 1px solid #e6e6e6;
-}
-
-.footer:before {
- content: '';
- position: absolute;
- right: 0;
- bottom: 0;
- left: 0;
- height: 50px;
- overflow: hidden;
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
- 0 8px 0 -3px #f6f6f6,
- 0 9px 1px -3px rgba(0, 0, 0, 0.2),
- 0 16px 0 -6px #f6f6f6,
- 0 17px 2px -6px rgba(0, 0, 0, 0.2);
-}
-
-.todo-count {
- float: left;
- text-align: left;
-}
-
-.todo-count strong {
- font-weight: 300;
-}
-
-.filters {
- margin: 0;
- padding: 0;
- list-style: none;
- position: absolute;
- right: 0;
- left: 0;
-}
-
-.filters li {
- display: inline;
-}
-
-.filters li a {
- color: inherit;
- margin: 3px;
- padding: 3px 7px;
- text-decoration: none;
- border: 1px solid transparent;
- border-radius: 3px;
-}
-
-.filters li a.selected,
-.filters li a:hover {
- border-color: rgba(175, 47, 47, 0.1);
-}
-
-.filters li a.selected {
- border-color: rgba(175, 47, 47, 0.2);
-}
-
-.clear-completed,
-html .clear-completed:active {
- float: right;
- position: relative;
- line-height: 20px;
- text-decoration: none;
- cursor: pointer;
-}
-
-.clear-completed:hover {
- text-decoration: underline;
-}
-
-.info {
- margin: 65px auto 0;
- color: #bfbfbf;
- font-size: 10px;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- text-align: center;
-}
-
-.info p {
- line-height: 1;
-}
-
-.info a {
- color: inherit;
- text-decoration: none;
- font-weight: 400;
-}
-
-.info a:hover {
- text-decoration: underline;
-}
-
-/*
- Hack to remove background from Mobile Safari.
- Can't use it globally since it destroys checkboxes in Firefox
-*/
-@media screen and (-webkit-min-device-pixel-ratio:0) {
- .toggle-all,
- .todo-list li .toggle {
- background: none;
- }
-
- .todo-list li .toggle {
- height: 40px;
- }
-
- .toggle-all {
- -webkit-transform: rotate(90deg);
- transform: rotate(90deg);
- -webkit-appearance: none;
- appearance: none;
- }
-}
-
-@media (max-width: 430px) {
- .footer {
- height: 50px;
- }
-
- .filters {
- bottom: 10px;
- }
-}
diff --git a/test/assets/todo.spec.ts b/test/assets/todo.spec.ts
index 28e0d34..5b2ad17 100644
--- a/test/assets/todo.spec.ts
+++ b/test/assets/todo.spec.ts
@@ -4,20 +4,20 @@ import {
inject,
beforeEachProviders,
TestComponentBuilder
-} from "@angular/core/testing"
-import { Todo } from "./app/services/store"
+} from '@angular/core/testing';
+import { Todo } from './app/services/store';
// class MockTodoStorage implements TodoStorage {}
// #docregion describeIt
-describe("some component", () => {
- it("does something", () => {
+describe('some component', () => {
+ it('does something', () => {
const todo = {
completed: true,
editing: true,
- title: "bla"
- }
+ title: 'bla'
+ };
// This is a test.
- console.log("running js test "+JSON.stringify(todo))
- })
-})
\ No newline at end of file
+ console.log('running js test '+JSON.stringify(todo));
+ });
+});
diff --git a/tsconfig.json b/tsconfig.json
index 388f559..ed8286f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -22,11 +22,8 @@
]
},
/* noImplicitAny when you want your typescript to be fully typed */
- "noImplicitAny":true,
- "noFallthroughCasesInSwitch":true,
- "noImplicitReturns":true,
- "noImplicitThis":true,
- // "strictNullChecks":true, doesn't work yet with @angular RC4
+ "strict":true,
+ "strictNullChecks":false, //doesn't work yet with @angular RC4
"outDir": "./target/ts",
"lib": ["es6", "dom"]
},
@@ -39,4 +36,4 @@
"typings/browser",
"target/web"
]
-}
\ No newline at end of file
+}
diff --git a/tslint.json b/tslint.json
index 824e204..4f2e5db 100644
--- a/tslint.json
+++ b/tslint.json
@@ -1,83 +1,39 @@
{
+ "extends": "tslint:recommended",
+ "lintOptions": {
+ "fix": true
+ },
"rules": {
/* ng2 rules */
- "directive-selector-name": [true, "camelCase"],
- "component-selector-name": [true, "kebab-case"],
- "directive-selector-type": [true, "attribute"],
- "component-selector-type": [true, "element"],
- "directive-selector-prefix": [true, "todo"],
- "component-selector-prefix": [true, "todo"],
- "use-input-property-decorator": true,
- "use-output-property-decorator": true,
- "use-host-property-decorator": true,
- "no-attribute-parameter-decorator": true,
- "no-input-rename": true,
- "no-output-rename": true,
- "no-forward-ref" :true,
- "use-life-cycle-interface": true,
- "use-pipe-transform-interface": true,
- "pipe-naming": [true, "camelCase", "todo"],
- "component-class-suffix": true,
- "directive-class-suffix": true,
- "import-destructuring-spacing": false,
+// "directive-selector": [true, "attribute", "sg", "camelCase"],
+// "component-selector": [true, "element", "sg", "kebab-case"],
+// "use-input-property-decorator": true,
+// "use-output-property-decorator": true,
+// "use-host-property-decorator": true,
+// "no-attribute-parameter-decorator": true,
+// "no-input-rename": true,
+// "no-output-rename": true,
+// "no-forward-ref": true,
+// "use-life-cycle-interface": true,
+// "use-pipe-transform-interface": true,
+// "pipe-naming": [true, "camelCase", "sg"],
+// "component-class-suffix": true,
+// "directive-class-suffix": true,
+// "import-destructuring-spacing": true,
+// "templates-use-public": true,
+// "no-access-missing-member": true,
+// "invoke-injectable": true,
"no-empty": true, /* this is an eslint rule */
- /* the following rules are tslint rules */
- "class-name": true,
- "comment-format": [
- true,
- "check-space"
- ],
- "indent": [
- true,
- "spaces"
- ],
- "no-duplicate-variable": true,
- "no-eval": true,
- "no-internal-module": true,
- "no-trailing-whitespace": true,
- "no-var-keyword": true,
- "one-line": [
- true,
- "check-open-brace",
- "check-whitespace"
- ],
- "quotemark": [
- true,
- "double"
- ],
- "semicolon": [
- true,
- "never"
- ],
- "triple-equals": [
- true,
- "allow-null-check"
- ],
- "typedef-whitespace": [
- true,
- {
- "call-signature": "nospace",
- "index-signature": "nospace",
- "parameter": "nospace",
- "property-declaration": "nospace",
- "variable-declaration": "nospace"
- }
- ],
- "variable-name": [
- true,
- "ban-keywords"
- ],
- "whitespace": [
- false,
- "check-branch",
- "check-decl",
- "check-operator",
- "check-separator",
- "check-type"
- ]
+ /* you can override any of the default tslint rules provided by 'tslint:recommended' */
+ "object-literal-sort-keys": false,
+ "quotemark": [true, "single", "avoid-escape"],
+ "ordered-imports": false,
+ "arrow-parens": false,
+ "object-literal-shorthand": false,
+ "import-spacing": false
}
}
diff --git a/typings.json b/typings.json
deleted file mode 100644
index b8a8f2e..0000000
--- a/typings.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "dependencies": {
- },
- "ambientDependencies": {
- "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#5c182b9af717f73146399c2485f70f1e2ac0ff2b"
- }
-}
diff --git a/typings/index.d.ts b/typings/index.d.ts
deleted file mode 100644
index 8b13789..0000000
--- a/typings/index.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-