├── .editorconfig
├── .gitignore
├── .jshintrc
├── LICENSE
├── README.md
├── app
├── bootstrap.ts
├── components
│ ├── about
│ │ ├── about.html
│ │ ├── about.ts
│ │ └── about_spec.ts
│ ├── app
│ │ ├── app.css
│ │ ├── app.html
│ │ └── app.ts
│ ├── home
│ │ ├── home.css
│ │ ├── home.html
│ │ ├── home.ts
│ │ └── home_spec.ts
│ └── users
│ │ ├── services
│ │ ├── interfaces.ts
│ │ └── user_service.ts
│ │ ├── user_details
│ │ ├── user_details.html
│ │ └── user_details.ts
│ │ ├── user_form
│ │ ├── user_form.html
│ │ └── user_form.ts
│ │ ├── users.css
│ │ ├── users.html
│ │ ├── users.ts
│ │ ├── users_home
│ │ ├── users_home.html
│ │ └── users_home.ts
│ │ └── users_list
│ │ ├── users_list.html
│ │ └── users_list.ts
├── directives
│ ├── loading_btn.ts
│ └── set_active.ts
├── index.html
└── services
│ ├── component_proxy.ts
│ ├── name_list.ts
│ └── name_list_spec.ts
├── gulpfile.ts
├── karma.conf.js
├── package.json
├── test-main.js
├── tools
├── config.ts
├── tasks
│ ├── build.bundles.ts
│ ├── build.deps.ts
│ ├── build.docs.ts
│ ├── build.html_css.prod.ts
│ ├── build.img.dev.ts
│ ├── build.index.ts
│ ├── build.js.dev.ts
│ ├── build.js.prod.ts
│ ├── build.sass.dev.ts
│ ├── build.test.ts
│ ├── check.versions.ts
│ ├── clean.ts
│ ├── karma.start.ts
│ ├── npm.ts
│ ├── serve.docs.ts
│ ├── server.start.ts
│ ├── tsd.ts
│ ├── tslint.ts
│ ├── watch.dev.ts
│ ├── watch.serve.ts
│ └── watch.test.ts
├── typings
│ ├── connect-livereload.d.ts
│ ├── gulp-load-plugins.d.ts
│ ├── karma.d.ts
│ ├── merge-stream.d.ts
│ ├── open.d.ts
│ ├── run-sequence.d.ts
│ ├── slash.d.ts
│ ├── systemjs-builder.d.ts
│ ├── tiny-lr.d.ts
│ └── yargs.d.ts
├── utils.ts
└── utils
│ ├── server.ts
│ ├── tasks_tools.ts
│ ├── template-injectables.ts
│ └── template-locals.ts
├── tsconfig.json
├── tsd.json
└── tslint.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Commenting this out is preferred by some people, see
24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
25 | node_modules
26 |
27 | # Users Environment Variables
28 | .lock-wscript
29 | .tsdrc
30 |
31 | #IDE configuration files
32 | .idea
33 | .vscode
34 |
35 | dist
36 | dev
37 | docs
38 | lib
39 | test
40 | tools/typings/tsd
41 | tmp
42 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "bitwise": true,
3 | "immed": true,
4 | "newcap": true,
5 | "noarg": true,
6 | "noempty": true,
7 | "nonew": true,
8 | "trailing": true,
9 | "maxlen": 200,
10 | "boss": true,
11 | "eqnull": true,
12 | "expr": true,
13 | "globalstrict": true,
14 | "laxbreak": true,
15 | "loopfunc": true,
16 | "sub": true,
17 | "undef": true,
18 | "indent": 2,
19 | "unused": true,
20 |
21 | "node": true,
22 | "globals": {
23 | "System": true
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Minko Gechev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WARNING
2 |
3 | This project is no longer maintained. For Angular 2 starter take a look at the [angular2-seed](https://github.com/mgechev/angular2-seed), that this project is based on.
4 |
5 | # Introduction
6 |
7 | Sample application based upon [mgechev](https://github.com/mgechev)/ [angular2-seed](https://github.com/mgechev/angular2-seed).
8 |
9 | [](https://gitter.im/mgechev/angular2-seed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10 | [](https://david-dm.org/mgechev/angular2-seed)
11 | [](https://david-dm.org/mgechev/angular2-seed#info=devDependencies)
12 |
13 | **Note:** Angular 2.0 is not production ready yet! This project is perfect for playing around with the latest versions but do not start new projects with it since a lot of new changes are going to be introduced until the framework is officially released.
14 |
15 | # Features
16 |
17 | * Component styling
18 | * Custom Directive
19 | * Router module (implementing child routes*)
20 | * Http module
21 | * Form module (using template driven form approach)
22 |
23 | # How to start
24 |
25 | **Note** that this seed project requires node v0.12.x or higher and npm 3.x.x.
26 |
27 | ```bash
28 | npm install
29 | # dev
30 | npm run serve.dev
31 | ```
32 | _Does not rely on any global dependencies._
33 |
34 | # Directory Structure
35 |
36 | ```
37 | .
38 | ├── app
39 | │ ├── components
40 | │ │ ├── about
41 | │ │ │ ├── about.html
42 | │ │ │ ├── about.ts
43 | │ │ │ └── about_spec.ts
44 | │ │ └── home
45 | │ │ ├── home.css
46 | │ │ ├── home.html
47 | │ │ ├── home.ts
48 | │ │ └── home_spec.ts
49 | │ ├── services
50 | │ │ ├── name_list.ts
51 | │ │ └── name_list_spec.ts
52 | │ ├── typings
53 | │ ├── app.css
54 | │ ├── app.html
55 | │ ├── app.ts
56 | │ ├── index.html
57 | │ └── init.ts
58 | ├── dist
59 | │ ├── dev
60 | │ └── prod
61 | ├── tools
62 | │ ├── tasks
63 | │ ├── utils.js
64 | │ └── workflow.config.js
65 | ├── tsd_typings
66 | ├── gulpfile.js
67 | ├── karma.conf.js
68 | ├── package.json
69 | ├── test-main.js
70 | ├── tsconfig.json
71 | └── tsd.json
72 | ```
73 |
74 | # Configuration
75 |
76 | Default application server configuration
77 |
78 | ```javascript
79 | var PORT = 5555;
80 | var LIVE_RELOAD_PORT = 4002;
81 | var APP_BASE = '/';
82 | ```
83 |
84 | Configure at runtime
85 |
86 | ```bash
87 | npm run serve.dev -- --port 8080 --reload-port 4000 --base /my-app/
88 | ```
89 |
90 | # Now to extend?
91 |
92 | If you want to use your custom libraries:
93 |
94 | ```bash
95 | npm install my-library --save
96 | vim gulpfile.js
97 | ```
98 | Add reference to the installed library in `PATH.src.lib` into `./tools/workflow.config.js`.
99 |
100 | # Running test
101 |
102 | ```bash
103 | # In a single bash window
104 | npm run test
105 |
106 | # Debug - In two bash windows
107 | npm run karma # 1st window
108 | npm run test.dev # 2nd window
109 | ```
110 |
111 | # Contributors
112 |
113 | [
](https://github.com/mgechev) |[
](https://github.com/ludohenin) |[
](https://github.com/NathanWalker) |[
](https://github.com/tarlepp) |[
](https://github.com/aboeglin) |[
](https://github.com/jerryorta-dev) |
114 | :---: |:---: |:---: |:---: |:---: |:---: |
115 | [mgechev](https://github.com/mgechev) |[ludohenin](https://github.com/ludohenin) |[NathanWalker](https://github.com/NathanWalker) |[tarlepp](https://github.com/tarlepp) |[aboeglin](https://github.com/aboeglin) |[jerryorta-dev](https://github.com/jerryorta-dev) |
116 |
117 | [
](https://github.com/TuiKiken) |[
](https://github.com/ryzy) |[
](https://github.com/ultrasonicsoft) |[
](https://github.com/mjwwit) |[
](https://github.com/natarajanmca11) |[
](https://github.com/philipooo) |
118 | :---: |:---: |:---: |:---: |:---: |:---: |
119 | [TuiKiken](https://github.com/TuiKiken) |[ryzy](https://github.com/ryzy) |[ultrasonicsoft](https://github.com/ultrasonicsoft) |[mjwwit](https://github.com/mjwwit) |[natarajanmca11](https://github.com/natarajanmca11) |[philipooo](https://github.com/philipooo) |
120 |
121 | [
](https://github.com/redian) |[
](https://github.com/robertpenner) |[
](https://github.com/jgolla) |[
](https://github.com/dstockhammer) |
122 | :---: |:---: |:---: |:---: |
123 | [redian](https://github.com/redian) |[robertpenner](https://github.com/robertpenner) |[jgolla](https://github.com/jgolla) |[dstockhammer](https://github.com/dstockhammer) |
124 |
125 | # Change Log
126 |
127 | You can follow the [Angular 2 change log here](https://github.com/angular/angular/blob/master/CHANGELOG.md).
128 |
129 | # License
130 |
131 | MIT
132 |
--------------------------------------------------------------------------------
/app/bootstrap.ts:
--------------------------------------------------------------------------------
1 | import {provide} from 'angular2/core';
2 | import {bootstrap} from 'angular2/platform/browser';
3 | import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router';
4 | import {HTTP_PROVIDERS} from 'angular2/http';
5 | import {AppCmp} from './components/app/app';
6 |
7 | bootstrap(AppCmp, [
8 | ROUTER_PROVIDERS,
9 | provide(LocationStrategy, { useClass: HashLocationStrategy }),
10 | HTTP_PROVIDERS
11 | ]);
12 |
--------------------------------------------------------------------------------
/app/components/about/about.html:
--------------------------------------------------------------------------------
1 |
2 | For reward, here is a list of awesome computer scientists!
3 |
4 |
5 |
6 | You want more? Add them yourself!
7 |
8 |
12 |
15 |
--------------------------------------------------------------------------------
/app/components/about/about.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {NgFor} from 'angular2/common';
3 | import {NameList} from '../../services/name_list';
4 |
5 | @Component({
6 | selector: 'about',
7 | styles: [
8 | `
9 | ul li a {
10 | color:blue;
11 | cursor:pointer;
12 | }
13 | `
14 | ],
15 | templateUrl: './components/about/about.html',
16 | directives: [NgFor]
17 | })
18 | export class AboutCmp {
19 | constructor(public list: NameList) {}
20 | addName(newname): boolean {
21 | this.list.add(newname.value);
22 | newname.value = '';
23 | // prevent default form submit behavior to refresh the page
24 | return false;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/components/about/about_spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | describe,
3 | expect,
4 | injectAsync,
5 | it,
6 | setBaseTestProviders,
7 | TestComponentBuilder
8 | } from 'angular2/testing';
9 | import {Component, View} from 'angular2/core';
10 | import {DOM} from 'angular2/src/platform/dom/dom_adapter';
11 | import {AboutCmp} from './about';
12 | import {NameList} from '../../services/name_list';
13 | import {} from 'angular2/testing';
14 | import {
15 | TEST_BROWSER_PLATFORM_PROVIDERS,
16 | TEST_BROWSER_APPLICATION_PROVIDERS
17 | } from 'angular2/platform/testing/browser';
18 | setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS,
19 | TEST_BROWSER_APPLICATION_PROVIDERS);
20 |
21 |
22 | export function main() {
23 | describe('About component', () => {
24 | it('should work', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
25 | return tcb.overrideTemplate(TestComponent, '')
26 | .createAsync(TestComponent)
27 | .then((rootTC) => {
28 | rootTC.detectChanges();
29 |
30 | let aboutInstance = rootTC.debugElement.componentViewChildren[0].componentInstance;
31 | let aboutDOMEl = rootTC.debugElement.componentViewChildren[0].nativeElement;
32 |
33 | let nameListLen = function () {
34 | return aboutInstance.list.names.length;
35 | };
36 |
37 | expect(aboutInstance.list).toEqual(jasmine.any(NameList));
38 | expect(nameListLen()).toEqual(4);
39 | expect(DOM.querySelectorAll(aboutDOMEl, 'li').length).toEqual(nameListLen());
40 |
41 | aboutInstance.addName({value: 'Minko'});
42 | rootTC.detectChanges();
43 |
44 | expect(nameListLen()).toEqual(5);
45 | expect(DOM.querySelectorAll(aboutDOMEl, 'li').length).toEqual(nameListLen());
46 | expect(DOM.querySelectorAll(aboutDOMEl, 'li > span')[4].textContent).toEqual('Minko');
47 | });
48 | }));
49 | });
50 | }
51 |
52 | @Component({providers: [NameList], selector: 'test-cmp'})
53 | @View({directives: [AboutCmp]})
54 | class TestComponent {}
55 |
--------------------------------------------------------------------------------
/app/components/app/app.css:
--------------------------------------------------------------------------------
1 | .sample-app-content {
2 | font-family: Verdana;
3 | }
4 | .sample-app-content h1 {
5 | color: #999;
6 | font-size: 3em;
7 | }
8 | .sample-app-content h2 {
9 | color: #990000;
10 | font-size: 2em;
11 | }
12 | .sample-app-content p,
13 | .sample-app-content nav {
14 | padding: 30px;
15 | }
16 | .sample-app-content li,
17 | .sample-app-content p {
18 | font-size: 1.2em;
19 | }
20 | .sample-app-content li {
21 | font-family: Consolas;
22 | }
23 | .sample-app-content nav a {
24 | display: inline-block;
25 | margin-right: 15px;
26 | }
27 | .sample-app-content input,
28 | .sample-app-content button {
29 | padding: 5px;
30 | font-size: 1em;
31 | outline: none;
32 | }
33 |
--------------------------------------------------------------------------------
/app/components/app/app.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/components/app/app.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewEncapsulation} from 'angular2/core';
2 | import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router';
3 |
4 | import {HomeCmp} from '../home/home';
5 | import {NameList} from '../../services/name_list';
6 | import {UsersCmp} from '../users/users';
7 | import {UserService} from '../users/services/user_service';
8 |
9 | import {componentProxyFactory} from '../../services/component_proxy';
10 |
11 | @Component({
12 | selector: 'app',
13 | viewProviders: [NameList, UserService],
14 | templateUrl: './components/app/app.html',
15 | styleUrls: ['./components/app/app.css'],
16 | encapsulation: ViewEncapsulation.None,
17 | directives: [ROUTER_DIRECTIVES]
18 | })
19 | @RouteConfig([
20 | { path: '/home', component: HomeCmp, as: 'Home', useAsDefault: true },
21 | {
22 | path: '/about',
23 | component: componentProxyFactory({
24 | path: './components/about/about',
25 | provide: m => m.AboutCmp
26 | }),
27 | as: 'About'
28 | },
29 | { path: '/users/...', component: UsersCmp, as: 'Users' }
30 | ])
31 | export class AppCmp {}
32 |
--------------------------------------------------------------------------------
/app/components/home/home.css:
--------------------------------------------------------------------------------
1 | .note {
2 | color: #a8a8a8;
3 | }
4 |
--------------------------------------------------------------------------------
/app/components/home/home.html:
--------------------------------------------------------------------------------
1 | Howdy!
2 |
3 |
4 | Gratz!
5 |
6 |
7 |
8 | Your deployment of Angular 2 Seed worked perfectly!
9 | Click about (above) to get your reward!
10 |
11 |
--------------------------------------------------------------------------------
/app/components/home/home.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 |
3 | @Component({
4 | selector: 'home',
5 | templateUrl: './components/home/home.html',
6 | styleUrls: ['./components/home/home.css']
7 | })
8 | export class HomeCmp {}
9 |
--------------------------------------------------------------------------------
/app/components/home/home_spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | describe,
3 | expect,
4 | injectAsync,
5 | it,
6 | setBaseTestProviders,
7 | TestComponentBuilder
8 | } from 'angular2/testing';
9 | import {Component, View} from 'angular2/core';
10 | import {DOM} from 'angular2/src/platform/dom/dom_adapter';
11 | import {HomeCmp} from './home';
12 | import {
13 | TEST_BROWSER_PLATFORM_PROVIDERS,
14 | TEST_BROWSER_APPLICATION_PROVIDERS
15 | } from 'angular2/platform/testing/browser';
16 | setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS,
17 | TEST_BROWSER_APPLICATION_PROVIDERS);
18 |
19 |
20 | export function main() {
21 | describe('Home component', () => {
22 | it('should work', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
23 | return tcb.overrideTemplate(TestComponent, '
')
24 | .createAsync(TestComponent)
25 | .then((rootTC) => {
26 | let homeDOMEl = rootTC.debugElement.componentViewChildren[0].nativeElement;
27 |
28 | expect(DOM.querySelectorAll(homeDOMEl, 'h1')[0].textContent).toEqual('Howdy!');
29 | });
30 | }));
31 | });
32 | }
33 |
34 | @Component({selector: 'test-cmp'})
35 | @View({directives: [HomeCmp]})
36 | class TestComponent {}
37 |
--------------------------------------------------------------------------------
/app/components/users/services/interfaces.ts:
--------------------------------------------------------------------------------
1 | export interface IUser {
2 | HETU: string;
3 | cell: string;
4 | dob: string;
5 | email: string;
6 | gender: string;
7 | location: {
8 | city: string;
9 | region: string;
10 | street: string;
11 | zip: string;
12 | };
13 | md5: string;
14 | name: {
15 | title: string;
16 | first: string;
17 | last: string;
18 | };
19 | nationality: string;
20 | password: string;
21 | phone: string;
22 | picture: {
23 | large: string;
24 | medium: string;
25 | thumbnail: string;
26 | };
27 | registered: string;
28 | salt: string;
29 | sha1: string;
30 | sha256: string;
31 | username: string;
32 | version: string;
33 | }
34 |
--------------------------------------------------------------------------------
/app/components/users/services/user_service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable, EventEmitter} from 'angular2/core';
2 | import {Http} from 'angular2/http';
3 | import 'rxjs/add/operator/map';
4 | import {IUser} from './interfaces';
5 |
6 | const SEED_URL = 'http://api.randomuser.me/?results=10&seed=885ad8c4404e07ea03';
7 | const URL = 'http://api.randomuser.me/?results=10';
8 |
9 | export {IUser} from './interfaces';
10 | @Injectable()
11 | export class UserService {
12 | // Fetch only once and cache the initial collection.
13 | usersCache = >[];
14 | loading = false;
15 | currentUser: IUser;
16 | currentFetches = new Map>>();
17 | loadingStatus: EventEmitter = new EventEmitter();
18 | constructor(private http: Http) {}
19 | getUsers(): Promise> {
20 | if (this.usersCache.length) {
21 | return new Promise((resolve) => resolve(this.usersCache));
22 | } else {
23 | return this.fetch(SEED_URL);
24 | }
25 | }
26 | getMoreUsers(): Promise> {
27 | return this.fetch(URL);
28 | }
29 | getUser(username): Promise {
30 | return this.findUserByUsername(username)
31 | .then(user => {
32 | this.currentUser = user;
33 | return this.currentUser;
34 | });
35 | }
36 | toggleState(force: boolean) {
37 | if (typeof force === 'undefined') {
38 | this.loading = !this.loading;
39 | } else {
40 | this.loading = force;
41 | }
42 | this.loadingStatus.emit(this.loading);
43 | }
44 | saveUser(user: IUser) {
45 | this.usersCache.push(user);
46 | this.sort();
47 | }
48 | sort() {
49 | this.usersCache.sort((a,b) => a.name.last > b.name.last? 1 : -1);
50 | }
51 | private fetch(url: string): Promise> {
52 | if (!this.currentFetches.has(url)) {
53 | let promise = new Promise((resolve, reject) => {
54 | this.toggleState(true);
55 | this.http.get(url)
56 | // .toRx()
57 | // Cleanup what is received from the API.
58 | .map(res => res.json().results)
59 | .map(res => res.map(o => o.user))
60 | .subscribe(res => {
61 | res.forEach(user => this.usersCache.push(user));
62 | this.sort();
63 | this.toggleState(false);
64 | this.currentFetches.delete(url);
65 | resolve(this.usersCache);
66 | });
67 | });
68 | this.currentFetches.set(url, promise);
69 | }
70 | return this.currentFetches.get(url);
71 | }
72 | private findUserByUsername(username): Promise {
73 | return new Promise(resolve => {
74 | this.getUsers().then(users => {
75 | let user = users.filter(user => user.username === username)[0];
76 | resolve(user);
77 | });
78 | });
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/components/users/user_details/user_details.html:
--------------------------------------------------------------------------------
1 |
2 |
No user found
3 |
4 |
5 |
User Details
6 |
7 | Firstname: {{ user.name.first }}
8 |
9 |
10 | Lastname: {{ user.name.last }}
11 |
12 |
13 |
14 |
15 |
16 | Edit
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/components/users/user_details/user_details.ts:
--------------------------------------------------------------------------------
1 | import {Component, Inject, OnInit} from 'angular2/core';
2 | import {RouteParams, RouterLink} from 'angular2/router';
3 | import {UserService, IUser} from '../services/user_service';
4 |
5 | @Component({
6 | selector: 'user-details',
7 | templateUrl: './components/users/user_details/user_details.html',
8 | directives: [RouterLink]
9 | })
10 | export class UserDetailsCmp implements OnInit {
11 | user: IUser;
12 | username: string;
13 | constructor(@Inject(RouteParams) routeParams,
14 | private userService: UserService) {
15 | this.username = routeParams.params.username;
16 | }
17 | ngOnInit() {
18 | this.userService
19 | .getUser(this.username)
20 | .then(user => this.user = user);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/components/users/user_form/user_form.html:
--------------------------------------------------------------------------------
1 | User Form
2 |
3 |
4 |
28 |
--------------------------------------------------------------------------------
/app/components/users/user_form/user_form.ts:
--------------------------------------------------------------------------------
1 | import {Component, Inject} from 'angular2/core';
2 | import {RouteParams} from 'angular2/router';
3 | import {UserService, IUser} from '../services/user_service';
4 |
5 | @Component({
6 | selector: 'user-form',
7 | templateUrl: './components/users/user_form/user_form.html'
8 | })
9 | export class UserFormCmp {
10 | user: IUser;
11 | username: string = this.routeParams.params ? this.routeParams.params.username : undefined;
12 | constructor(@Inject(RouteParams) private routeParams,
13 | private userService: UserService) {
14 | if (this.username) {
15 | userService.getUser(this.username)
16 | .then(user => this.user = user);
17 | } else {
18 | // TODO: add User model
19 | this.user = { name: { first: '', last: '' } };
20 | }
21 | }
22 | onSave(model) {
23 | if (this.username) {
24 | this.user.name.first = model.name.first;
25 | this.user.name.last = model.name.last;
26 | return;
27 | }
28 | // Fix as user-details expect a picture property.
29 | // ng2 does not fail silently when a property isn't
30 | // defined on a binding.
31 | model.picture = {};
32 | this.userService.saveUser(model);
33 | return false;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/components/users/users.css:
--------------------------------------------------------------------------------
1 | users,
2 | users-list,
3 | users-home,
4 | user-details { display: block; }
5 |
6 | ul.users-list {
7 | margin: 0;
8 | padding: 0;
9 | display: block;
10 | width: 280px;
11 | float: left;
12 | }
13 | .users-list > li {
14 | list-style: none;
15 | position: relative;
16 | font-size: 14px;
17 | }
18 | .users-list > li.active {
19 | background-color: #cecece;
20 | }
21 | .users-list > li > a {
22 | display: block;
23 | text-decoration: none;
24 | padding: 3px 0;
25 | color: dimgray;
26 | }
27 | .users-list > li > a.router-link-active {
28 | background-color:#28b0ed;
29 | color:#fff;
30 | }
31 | .users-list > li:hover {
32 | background-color: slategray;
33 | color: floralwhite;
34 | }
35 | .users-list > li:hover > a {
36 | color: floralwhite;
37 | }
38 |
39 | .users-list > li > a > img {
40 | width: 50px;
41 | height: 50px;
42 | border-radius: 25px;
43 | margin: 0 5px 0 5px;
44 | vertical-align: middle;
45 | }
46 | .users-list > li > .actions {
47 | display: none;
48 | position: absolute;
49 | right: 20px;
50 | top: 15px;
51 | }
52 | .users-list > li > .actions > a {
53 | color: floralwhite;
54 | }
55 | .users-list > li:hover > .actions {
56 | display: block;
57 | }
58 |
59 | .user-details {
60 | margin-left: 280px;
61 | padding: 0 15px;
62 | }
63 |
--------------------------------------------------------------------------------
/app/components/users/users.html:
--------------------------------------------------------------------------------
1 | Users
2 |
3 | Loading users data
4 |
5 |
6 |
12 |
13 |
Create user
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/components/users/users.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewEncapsulation} from 'angular2/core';
2 | import {RouteConfig, ROUTER_DIRECTIVES, CanActivate, OnActivate, ComponentInstruction} from 'angular2/router';
3 |
4 | import {UsersListCmp} from './users_list/users_list';
5 | import {UsersHomeCmp} from './users_home/users_home';
6 | import {UserDetailsCmp} from './user_details/user_details';
7 | import {UserFormCmp} from './user_form/user_form';
8 | import {UserService} from './services/user_service';
9 |
10 | import {LoadingBtn} from '../../directives/loading_btn';
11 |
12 | @Component({
13 | selector: 'users',
14 | templateUrl: './components/users/users.html',
15 | styleUrls: ['./components/users/users.css'],
16 | encapsulation: ViewEncapsulation.None,
17 | directives: [ROUTER_DIRECTIVES, UsersListCmp, LoadingBtn]
18 | })
19 | @RouteConfig([
20 | { path: '/home', component: UsersHomeCmp, as: 'Users-home', useAsDefault: true },
21 | { path: '/show/:username', component: UserDetailsCmp, as: 'User-details' },
22 | { path: '/edit/:username', component: UserFormCmp, as: 'User-edit' },
23 | { path: '/create', component: UserFormCmp, as: 'User-create' }
24 | ])
25 | @CanActivate((next: ComponentInstruction, prev: ComponentInstruction) => {
26 | console.info('Component router CanActivate hook! - can return boolean or Promise');
27 | return true;
28 | })
29 | export class UsersCmp implements OnActivate {
30 | public loading:boolean = true;
31 | constructor(public userService: UserService) {
32 | this.userService
33 | .getUsers()
34 | .then(users => {
35 | // To be removed when component activation will work.
36 | this.loading = false;
37 | });
38 | }
39 | eventHandler(value: any) {
40 | console.log(`Example of handling custom events: ${value}`);
41 | }
42 | routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
43 | console.info('Component routerOnActivate works!');
44 | this.loading = false;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/components/users/users_home/users_home.html:
--------------------------------------------------------------------------------
1 | Users Home
2 |
--------------------------------------------------------------------------------
/app/components/users/users_home/users_home.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 |
3 | @Component({
4 | selector: 'users-home',
5 | templateUrl: './components/users/users_home/users_home.html'
6 | })
7 | export class UsersHomeCmp {}
8 |
--------------------------------------------------------------------------------
/app/components/users/users_list/users_list.html:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/components/users/users_list/users_list.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/core';
2 | import {RouterLink} from 'angular2/router';
3 |
4 | import {SetActive} from '../../../directives/set_active';
5 |
6 | @Component({
7 | selector: 'users-list',
8 | inputs: ['users'],
9 | templateUrl: './components/users/users_list/users_list.html',
10 | directives: [RouterLink, SetActive]
11 | })
12 | export class UsersListCmp {}
13 |
--------------------------------------------------------------------------------
/app/directives/loading_btn.ts:
--------------------------------------------------------------------------------
1 | import {Directive, ElementRef, EventEmitter, Output, Input} from 'angular2/core';
2 | /**
3 | * Simple directive to display an action message (via [loading-text] property) in a button when clicked.
4 | * The button is then disabled until the action is completed.
5 | * It handles state via the [loading-more] property.
6 | * Shows how an example of how to emit custom events (sample-custom-event) with a value.
7 | *
8 | * @Example:
9 | *
17 | */
18 | @Directive({
19 | selector: 'button[loading-btn]',
20 | host: {
21 | '[disabled]': '_loading'
22 | }
23 | })
24 | export class LoadingBtn {
25 | @Input() public loadingText: string = 'Loading...';
26 | private _loading: boolean = false;
27 | private _originalText: string;
28 | @Output() private sampleCustomEvent = new EventEmitter();
29 | constructor(private _elRef: ElementRef) {
30 | this._originalText = this._elRef.nativeElement.innerText;
31 | }
32 | toggleText(): void {
33 | if (this._loading) {
34 | this._elRef.nativeElement.innerText = this.loadingText;
35 | } else {
36 | this._elRef.nativeElement.innerText = this._originalText;
37 | }
38 | }
39 | @Input('loadingMore') set loading(v: boolean) {
40 | this.sampleCustomEvent.emit(`Button is ${v ? '' : 'not '}loading.`);
41 | this._loading = v;
42 | this.toggleText();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/directives/set_active.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Directive,
3 | ElementRef,
4 | Inject,
5 | Renderer,
6 | QueryList,
7 | Query
8 | } from 'angular2/core';
9 | import {Location} from 'angular2/router';
10 | import 'rxjs/add/operator/map';
11 |
12 | /**
13 | * Simple directive to add class active on a LI element when
14 | * its A child element is clicked or on page load. Active class
15 | * is removed from all other LI element.
16 | * Follow the same principle as nav's in Bootstrap.
17 | *
18 | * @Example:
19 | *
20 | * -
21 | * link 1
22 | *
23 | * -
24 | * link 2
25 | *
26 | *
27 | */
28 | @Directive({ selector: 'a' })
29 | class Link {
30 | constructor (private el: ElementRef) {}
31 | get href(): string {
32 | // Rely on the DOM until there is a better option.
33 | // The problem is that the href attribute is generated by router-link
34 | // directive which is instantiated after this one. href is then not
35 | // available at that time.
36 | return this.el.nativeElement.getAttribute('href');
37 | }
38 | }
39 |
40 | @Directive({ selector: 'li' })
41 | class ListItem {
42 | className = 'active';
43 | constructor(@Query(Link) public links: QueryList,
44 | @Inject(Location) public location: Location,
45 | private el: ElementRef,
46 | private renderer: Renderer) {}
47 | toggleClass() {
48 | if (this.linkHref === `#${this.location.path()}`) {
49 | this.renderer.setElementClass(this.el, this.className, true);
50 | } else {
51 | this.renderer.setElementClass(this.el, this.className, false);
52 | }
53 | }
54 | get linkHref(): string {
55 | return this.links.first.href;
56 | }
57 | }
58 |
59 | @Directive({ selector: '[set-active]', host: { '(click)': 'setActive()' } })
60 | class List {
61 | _href;
62 | constructor(@Query(ListItem) private items: QueryList) {
63 | // _items is populated later on as it's refers to child classes.
64 | // So we wait for changes.
65 | // TODO: Figure out the changes needed here to make this work again
66 | this.items.changes.subscribe(_ => {
67 | this.setActive();
68 | });
69 | }
70 | setActive(): void {
71 | this.items.map(item => {
72 | item.toggleClass();
73 | });
74 | }
75 | }
76 |
77 | export var SetActive = [List, ListItem, Link];
78 |
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= APP_TITLE %>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Loading...
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/services/component_proxy.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {
4 | Component,
5 | DynamicComponentLoader,
6 | ElementRef,
7 | Injector,
8 | provide,
9 | Type,
10 | View
11 | } from 'angular2/core';
12 | /**
13 | * A factory for a Virtual Proxy Component
14 | * to provide a lazily loaded `Component` which will be loaded and rendered by the `DynamicComponentLoader` on entering a route when
15 | * the constructor of the Virtual Component is executed.
16 | *
17 | * @Example:
18 | * {
19 | * path: '/path-in-the-browser',
20 | * component: componentProxyFactory({
21 | * path: './path/to/the/file',
22 | * provide: m => m.ClassNameOfComponent
23 | * }),
24 | * as: 'ComponentName'
25 | * }
26 | *
27 | */
28 |
29 | class ComponentProvider {
30 | path: string;
31 | provide: {(module: any): any};
32 | }
33 |
34 | export function componentProxyFactory(provider: ComponentProvider): Type {
35 | @Component({
36 | selector: 'component-proxy',
37 | providers: [provide(ComponentProvider, {useValue: provider})]
38 | })
39 | @View({
40 | template: ``
41 | })
42 | class VirtualComponent {
43 | constructor(
44 | el: ElementRef,
45 | loader: DynamicComponentLoader,
46 | inj: Injector,
47 | provider: ComponentProvider
48 | ) {
49 | System.import(provider.path)
50 | .then(m => {
51 | loader.loadIntoLocation(provider.provide(m), el, 'content');
52 | });
53 | }
54 | }
55 | return VirtualComponent;
56 | }
57 |
--------------------------------------------------------------------------------
/app/services/name_list.ts:
--------------------------------------------------------------------------------
1 | export class NameList {
2 | names = ['Dijkstra', 'Knuth', 'Turing', 'Hopper'];
3 |
4 | get(): string[] {
5 | return this.names;
6 | }
7 | add(value: string):void {
8 | this.names.push(value);
9 | }
10 | remove(index: number):void {
11 | this.names.splice(index, 1);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/services/name_list_spec.ts:
--------------------------------------------------------------------------------
1 | import {NameList} from './name_list';
2 |
3 | export function main() {
4 | describe('NameList Service', () => {
5 | var nameList;
6 |
7 | beforeEach(() => {
8 | nameList = new NameList;
9 | });
10 |
11 | it('should return the list of names', () => {
12 | var names = nameList.get();
13 | expect(names).toEqual(jasmine.any(Array));
14 | });
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/gulpfile.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import {runSequence, task} from './tools/utils';
3 |
4 | // --------------
5 | // Clean (override).
6 | gulp.task('clean', task('clean', 'all'));
7 | gulp.task('clean.dist', task('clean', 'dist'));
8 | gulp.task('clean.test', task('clean', 'test'));
9 | gulp.task('clean.tmp', task('clean', 'tmp'));
10 |
11 | gulp.task('check.versions', task('check.versions'));
12 |
13 | // --------------
14 | // Postinstall.
15 | gulp.task('postinstall', done =>
16 | runSequence('clean',
17 | 'npm',
18 | done));
19 |
20 | // --------------
21 | // Build dev.
22 | gulp.task('build.dev', done =>
23 | runSequence('clean.dist',
24 | 'tslint',
25 | 'build.sass.dev',
26 | 'build.img.dev',
27 | 'build.js.dev',
28 | 'build.index',
29 | done));
30 |
31 | // --------------
32 | // Build prod.
33 | gulp.task('build.prod', done =>
34 | runSequence('clean.dist',
35 | 'clean.tmp',
36 | 'tslint',
37 | 'build.sass.dev',
38 | 'build.img.dev',
39 | 'build.html_css.prod',
40 | 'build.deps',
41 | 'build.js.prod',
42 | 'build.bundles',
43 | 'build.index',
44 | done));
45 |
46 | // --------------
47 | // Watch.
48 | gulp.task('build.dev.watch', done =>
49 | runSequence('build.dev',
50 | 'watch.dev',
51 | done));
52 |
53 | gulp.task('build.test.watch', done =>
54 | runSequence('build.test',
55 | 'watch.test',
56 | done));
57 |
58 | // --------------
59 | // Test.
60 | gulp.task('test', done =>
61 | runSequence('clean.test',
62 | 'tslint',
63 | 'build.test',
64 | 'karma.start',
65 | done));
66 |
67 | // --------------
68 | // Serve.
69 | gulp.task('serve', done =>
70 | runSequence('build.dev',
71 | 'server.start',
72 | 'watch.serve',
73 | done));
74 |
75 | // --------------
76 | // Docs
77 | // Disabled until https://github.com/sebastian-lenz/typedoc/issues/162 gets resolved
78 | // gulp.task('docs', done =>
79 | // runSequence('build.docs',
80 | // 'serve.docs',
81 | // done));
82 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Wed Jul 15 2015 09:44:02 GMT+0200 (Romance Daylight Time)
3 | 'use strict';
4 |
5 | module.exports = function(config) {
6 | config.set({
7 |
8 | // base path that will be used to resolve all patterns (eg. files, exclude)
9 | basePath: './',
10 |
11 |
12 | // frameworks to use
13 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
14 | frameworks: ['jasmine'],
15 |
16 |
17 | // list of files / patterns to load in the browser
18 | files: [
19 | 'node_modules/zone.js/dist/zone-microtask.js',
20 | 'node_modules/zone.js/dist/long-stack-trace-zone.js',
21 | 'node_modules/zone.js/dist/jasmine-patch.js',
22 | 'node_modules/es6-module-loader/dist/es6-module-loader.js',
23 | 'node_modules/traceur/bin/traceur-runtime.js', // Required by PhantomJS2, otherwise it shouts ReferenceError: Can't find variable: require
24 | 'node_modules/traceur/bin/traceur.js',
25 | 'node_modules/systemjs/dist/system.src.js',
26 | 'node_modules/reflect-metadata/Reflect.js',
27 |
28 | { pattern: 'node_modules/angular2/**/*.js', included: false, watched: false },
29 | { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
30 | { pattern: 'test/**/*.js', included: false, watched: true },
31 | { pattern: 'node_modules/systemjs/dist/system-polyfills.js', included: false, watched: false }, // PhantomJS2 (and possibly others) might require it
32 |
33 | 'test-main.js'
34 | ],
35 |
36 |
37 | // list of files to exclude
38 | exclude: [
39 | 'node_modules/angular2/**/*_spec.js'
40 | ],
41 |
42 |
43 | // preprocess matching files before serving them to the browser
44 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
45 | preprocessors: {
46 | },
47 |
48 |
49 | // test results reporter to use
50 | // possible values: 'dots', 'progress'
51 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
52 | reporters: ['mocha'],
53 |
54 |
55 | // web server port
56 | port: 9876,
57 |
58 |
59 | // enable / disable colors in the output (reporters and logs)
60 | colors: true,
61 |
62 |
63 | // level of logging
64 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
65 | logLevel: config.LOG_INFO,
66 |
67 |
68 | // enable / disable watching file and executing tests whenever any file changes
69 | autoWatch: true,
70 |
71 |
72 | // start these browsers
73 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
74 | browsers: [
75 | 'PhantomJS2',
76 | 'Chrome'
77 | ],
78 |
79 |
80 | customLaunchers: {
81 | Chrome_travis_ci: {
82 | base: 'Chrome',
83 | flags: ['--no-sandbox']
84 | }
85 | },
86 |
87 |
88 | // Continuous Integration mode
89 | // if true, Karma captures browsers, runs the tests and exits
90 | singleRun: false
91 | });
92 |
93 | if (process.env.APPVEYOR) {
94 | config.browsers = ['IE'];
95 | config.singleRun = true;
96 | config.browserNoActivityTimeout = 90000; // Note: default value (10000) is not enough
97 | }
98 |
99 | if (process.env.TRAVIS || process.env.CIRCLECI) {
100 | config.browsers = ['Chrome_travis_ci'];
101 | config.singleRun = true;
102 | }
103 | };
104 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular2-sample-app",
3 | "version": "0.0.0",
4 | "description": "Extended seed for Angular 2 apps",
5 | "repository": {
6 | "url": "https://github.com/AngularShowcase/angular2-sample-app"
7 | },
8 | "scripts": {
9 | "build.dev": "gulp build.dev",
10 | "build.dev.watch": "gulp build.dev.watch",
11 | "build.prod": "gulp build.prod --env prod",
12 | "build.test": "gulp build.test",
13 | "build.test.watch": "gulp build.test.watch",
14 | "docs": "npm run gulp -- build.docs && npm run gulp -- serve.docs",
15 | "gulp": "gulp",
16 | "karma": "karma",
17 | "karma.start": "karma start",
18 | "lint": "gulp tslint",
19 | "postinstall": "tsd reinstall --clean && tsd link && tsd rebundle && gulp check.versions && gulp postinstall",
20 | "reinstall": "rimraf node_modules && npm cache clean && npm install",
21 | "start": "gulp serve --env dev",
22 | "serve.dev": "gulp serve --env dev",
23 | "tasks.list": "gulp --tasks-simple",
24 | "test": "gulp test",
25 | "tsd": "tsd"
26 | },
27 | "author": "Minko Gechev ",
28 | "license": "MIT",
29 | "devDependencies": {
30 | "async": "^1.4.2",
31 | "chalk": "^1.1.1",
32 | "connect-livereload": "^0.5.3",
33 | "del": "^1.1.1",
34 | "express": "~4.13.1",
35 | "extend": "^3.0.0",
36 | "gulp": "^3.9.0",
37 | "gulp-concat": "^2.5.2",
38 | "gulp-filter": "^2.0.2",
39 | "gulp-inject": "^1.3.1",
40 | "gulp-inline-ng2-template": "^0.0.7",
41 | "gulp-load-plugins": "^0.10.0",
42 | "gulp-minify-css": "^1.1.6",
43 | "gulp-minify-html": "^1.0.3",
44 | "gulp-plumber": "~1.0.1",
45 | "gulp-sass": "^2.0.4",
46 | "gulp-shell": "~0.4.3",
47 | "gulp-sourcemaps": "~1.5.2",
48 | "gulp-template": "^3.0.0",
49 | "gulp-tslint": "^3.3.0",
50 | "gulp-tslint-stylish": "^1.0.4",
51 | "gulp-typescript": "~2.8.2",
52 | "gulp-uglify": "^1.2.0",
53 | "gulp-util": "^3.0.7",
54 | "gulp-watch": "^4.2.4",
55 | "jasmine-core": "~2.3.4",
56 | "karma": "~0.13.15",
57 | "karma-chrome-launcher": "~0.2.0",
58 | "karma-ie-launcher": "^0.2.0",
59 | "karma-jasmine": "~0.3.6",
60 | "karma-mocha-reporter": "^1.1.1",
61 | "karma-phantomjs2-launcher": "^0.3.2",
62 | "merge-stream": "^1.0.0",
63 | "open": "0.0.5",
64 | "rimraf": "^2.4.3",
65 | "run-sequence": "^1.1.0",
66 | "semver": "^5.0.3",
67 | "serve-static": "^1.9.2",
68 | "slash": "~1.0.0",
69 | "stream-series": "^0.1.1",
70 | "systemjs-builder": "^0.14.8",
71 | "tiny-lr": "^0.2.1",
72 | "traceur": "^0.0.91",
73 | "ts-node": "^0.5.4",
74 | "tsd": "^0.6.4",
75 | "typedoc": "^0.3.12",
76 | "typescript": "~1.7.3",
77 | "typescript-register": "^1.1.0",
78 | "yargs": "^3.25.0"
79 | },
80 | "dependencies": {
81 | "angular2": "2.0.0-beta.2",
82 | "bootstrap": "^3.3.6",
83 | "es6-module-loader": "^0.17.8",
84 | "es6-shim": "^0.33.3",
85 | "reflect-metadata": "^0.1.2",
86 | "rxjs": "5.0.0-beta.0",
87 | "systemjs": "^0.19.4",
88 | "zone.js": "0.5.10"
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/test-main.js:
--------------------------------------------------------------------------------
1 | // Turn on full stack traces in errors to help debugging
2 | Error.stackTraceLimit=Infinity;
3 |
4 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 100;
5 |
6 | // Cancel Karma's synchronous start,
7 | // we will call `__karma__.start()` later, once all the specs are loaded.
8 | __karma__.loaded = function() {};
9 |
10 | System.config({
11 | baseURL: '/base/',
12 | defaultJSExtensions: true,
13 | paths: {
14 | 'angular2/*': 'node_modules/angular2/*.js',
15 | 'rxjs/*': 'node_modules/rxjs/*.js'
16 | }
17 | });
18 |
19 | System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) {
20 | browser_adapter.BrowserDomAdapter.makeCurrent();
21 | }).then(function() {
22 | return Promise.all(
23 | Object.keys(window.__karma__.files) // All files served by Karma.
24 | .filter(onlySpecFiles)
25 | .map(file2moduleName)
26 | .map(function(path) {
27 | return System.import(path).then(function(module) {
28 | if (module.hasOwnProperty('main')) {
29 | module.main();
30 | } else {
31 | throw new Error('Module ' + path + ' does not implement main() method.');
32 | }
33 | });
34 | }));
35 | })
36 | .then(function() {
37 | __karma__.start();
38 | }, function(error) {
39 | console.error(error.stack || error);
40 | __karma__.start();
41 | });
42 |
43 |
44 | function onlySpecFiles(path) {
45 | return /[\.|_]spec\.js$/.test(path);
46 | }
47 |
48 | // Normalize paths to module names.
49 | function file2moduleName(filePath) {
50 | return filePath.replace(/\\/g, '/')
51 | .replace(/^\/base\//, '')
52 | .replace(/\.js/, '');
53 | }
54 |
--------------------------------------------------------------------------------
/tools/config.ts:
--------------------------------------------------------------------------------
1 | import {readFileSync} from 'fs';
2 | import {argv} from 'yargs';
3 |
4 |
5 | // --------------
6 | // Configuration.
7 | export const ENV = argv['env'] || 'dev';
8 | export const DEBUG = argv['debug'] || false;
9 | export const PORT = argv['port'] || 5555;
10 | export const LIVE_RELOAD_PORT = argv['reload-port'] || 4002;
11 | export const DOCS_PORT = argv['docs-port'] || 4003;
12 | export const APP_BASE = argv['base'] || '/';
13 |
14 | export const APP_TITLE = 'My Angular2 App';
15 |
16 | export const APP_SRC = 'app';
17 | export const ASSETS_SRC = `${APP_SRC}/assets`;
18 |
19 | export const TOOLS_DIR = 'tools';
20 | export const TMP_DIR = 'tmp';
21 | export const TEST_DEST = 'test';
22 | export const DOCS_DEST = 'docs';
23 | export const APP_DEST = `dist/${ENV}`;
24 | export const ASSETS_DEST = `${APP_DEST}/assets`;
25 | export const BUNDLES_DEST = `${APP_DEST}/bundles`;
26 | export const CSS_DEST = `${APP_DEST}/css`;
27 | export const FONTS_DEST = `${APP_DEST}/fonts`;
28 | export const LIB_DEST = `${APP_DEST}/lib`;
29 | export const APP_ROOT = ENV === 'dev' ? `${APP_BASE}${APP_DEST}/` : `${APP_BASE}`;
30 | export const VERSION = appVersion();
31 |
32 | export const VERSION_NPM = '2.14.7';
33 | export const VERSION_NODE = '4.0.0';
34 |
35 | // Declare NPM dependencies (Note that globs should not be injected).
36 | export const NPM_DEPENDENCIES = [
37 | { src: 'systemjs/dist/system-polyfills.js', dest: LIB_DEST },
38 |
39 | { src: 'es6-shim/es6-shim.min.js', inject: 'shims', dest: LIB_DEST },
40 | { src: 'reflect-metadata/Reflect.js', inject: 'shims', dest: LIB_DEST },
41 | { src: 'systemjs/dist/system.src.js', inject: 'shims', dest: LIB_DEST },
42 | { src: 'angular2/bundles/angular2-polyfills.js', inject: 'shims', dest: LIB_DEST },
43 |
44 | // Faster dev page load
45 | { src: 'rxjs/bundles/Rx.min.js', inject: 'libs', dest: LIB_DEST },
46 | { src: 'angular2/bundles/angular2.min.js', inject: 'libs', dest: LIB_DEST },
47 | { src: 'angular2/bundles/router.js', inject: 'libs', dest: LIB_DEST }, // use router.min.js with alpha47
48 | { src: 'angular2/bundles/http.min.js', inject: 'libs', dest: LIB_DEST },
49 |
50 | { src: 'bootstrap/dist/css/bootstrap.min.css', inject: true, dest: CSS_DEST }
51 | ];
52 |
53 | // Declare local files that needs to be injected
54 | export const APP_ASSETS = [
55 | { src: `${ASSETS_SRC}/main.css`, inject: true, dest: CSS_DEST }
56 | ];
57 |
58 | NPM_DEPENDENCIES
59 | .filter(d => !/\*/.test(d.src)) // Skip globs
60 | .forEach(d => d.src = require.resolve(d.src));
61 |
62 | export const DEPENDENCIES = NPM_DEPENDENCIES.concat(APP_ASSETS);
63 |
64 |
65 | // ----------------
66 | // SystemsJS Configuration.
67 | const SYSTEM_CONFIG_DEV = {
68 | defaultJSExtensions: true,
69 | paths: {
70 | 'bootstrap': `${APP_ROOT}bootstrap`,
71 | '*': `${APP_BASE}node_modules/*`
72 | }
73 | };
74 |
75 | const SYSTEM_CONFIG_PROD = {
76 | defaultJSExtensions: true,
77 | bundles: {
78 | 'bundles/app': ['bootstrap']
79 | }
80 | };
81 |
82 | export const SYSTEM_CONFIG = ENV === 'dev' ? SYSTEM_CONFIG_DEV : SYSTEM_CONFIG_PROD;
83 |
84 | // This is important to keep clean module names as 'module name == module uri'.
85 | export const SYSTEM_CONFIG_BUILDER = {
86 | defaultJSExtensions: true,
87 | paths: {
88 | '*': `${TMP_DIR}/*`,
89 | 'angular2/*': 'node_modules/angular2/*',
90 | 'rxjs/*': 'node_modules/rxjs/*'
91 | }
92 | };
93 |
94 |
95 | // --------------
96 | // Private.
97 | function appVersion(): number|string {
98 | var pkg = JSON.parse(readFileSync('package.json').toString());
99 | return pkg.version;
100 | }
101 |
--------------------------------------------------------------------------------
/tools/tasks/build.bundles.ts:
--------------------------------------------------------------------------------
1 | import {parallel} from 'async';
2 | import {join} from 'path';
3 | import * as Builder from 'systemjs-builder';
4 | import {BUNDLES_DEST, SYSTEM_CONFIG_BUILDER} from '../config';
5 |
6 | const BUNDLE_OPTS = {
7 | minify: true,
8 | sourceMaps: true,
9 | format: 'cjs'
10 | };
11 |
12 | export = function bundles(gulp, plugins) {
13 | return function (done) {
14 | let builder = new Builder(SYSTEM_CONFIG_BUILDER);
15 |
16 | parallel([
17 | bundleApp
18 | ], () => done());
19 |
20 | function bundleApp(done) {
21 | builder.bundle(
22 | 'bootstrap - angular2/*',
23 | join(BUNDLES_DEST, 'app.js'), BUNDLE_OPTS).then(done);
24 | }
25 | };
26 | };
27 |
--------------------------------------------------------------------------------
/tools/tasks/build.deps.ts:
--------------------------------------------------------------------------------
1 | import * as merge from 'merge-stream';
2 | import {DEPENDENCIES} from '../config';
3 |
4 | export = function buildDepsProd(gulp, plugins) {
5 | return function () {
6 | let stream = merge();
7 |
8 | DEPENDENCIES.forEach(dep => {
9 | stream.add(addStream(dep));
10 | });
11 |
12 | return stream;
13 |
14 | function addStream(dep) {
15 | let stream = gulp.src(dep.src);
16 | stream.pipe(gulp.dest(dep.dest));
17 | return stream;
18 | }
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/tools/tasks/build.docs.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC, APP_TITLE, DOCS_DEST} from '../config';
3 |
4 | export = function buildDocs(gulp, plugins, option) {
5 | return function() {
6 |
7 | let src = [
8 | join(APP_SRC, '**/*.ts'),
9 | '!' + join(APP_SRC, '**/*_spec.ts')
10 | ];
11 |
12 | return gulp.src(src)
13 | .pipe(plugins.typedoc({
14 | // TypeScript options (see typescript docs)
15 | module: 'commonjs',
16 | target: 'es5',
17 | includeDeclarations: true,
18 | // Output options (see typedoc docs)
19 | out: DOCS_DEST,
20 | json: join(DOCS_DEST , 'data/docs.json' ),
21 | name: APP_TITLE,
22 | ignoreCompilerErrors: false,
23 | experimentalDecorators: true,
24 | version: true
25 | }));
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/tools/tasks/build.html_css.prod.ts:
--------------------------------------------------------------------------------
1 | import * as merge from 'merge-stream';
2 | import {join} from 'path';
3 | import {APP_SRC, TMP_DIR} from '../config';
4 |
5 | // const HTML_MINIFIER_OPTS = { empty: true };
6 |
7 | export = function buildJSDev(gulp, plugins) {
8 | return function () {
9 |
10 | return merge(minifyHtml(), minifyCss());
11 |
12 | function minifyHtml() {
13 | return gulp.src(join(APP_SRC, '**/*.html'))
14 | // .pipe(plugins.minifyHtml(HTML_MINIFIER_OPTS))
15 | .pipe(gulp.dest(TMP_DIR));
16 | }
17 |
18 | function minifyCss() {
19 | return gulp.src(join(APP_SRC, '**/*.css'))
20 | .pipe(plugins.minifyCss())
21 | .pipe(gulp.dest(TMP_DIR));
22 | }
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/tools/tasks/build.img.dev.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC, APP_DEST} from '../config';
3 |
4 | export = function buildImagesDev(gulp, plugins) {
5 | return function () {
6 | return gulp.src([
7 | join(APP_SRC, '**/*.gif'),
8 | join(APP_SRC, '**/*.jpg'),
9 | join(APP_SRC, '**/*.png'),
10 | join(APP_SRC, '**/*.svg')
11 | ])
12 | .pipe(gulp.dest(APP_DEST));
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/tools/tasks/build.index.ts:
--------------------------------------------------------------------------------
1 | import {join, sep} from 'path';
2 | import {APP_SRC, APP_DEST, DEPENDENCIES, ENV} from '../config';
3 | import {transformPath, templateLocals} from '../utils';
4 |
5 | export = function buildIndexDev(gulp, plugins) {
6 | return function () {
7 | return gulp.src(join(APP_SRC, 'index.html'))
8 | // NOTE: There might be a way to pipe in loop.
9 | .pipe(inject('shims'))
10 | .pipe(inject('libs'))
11 | .pipe(inject())
12 | .pipe(plugins.template(templateLocals()))
13 | .pipe(gulp.dest(APP_DEST));
14 | };
15 |
16 |
17 | function inject(name?: string) {
18 | return plugins.inject(gulp.src(getInjectablesDependenciesRef(name), { read: false }), {
19 | name,
20 | transform: transformPath(plugins, 'dev')
21 | });
22 | }
23 |
24 | function getInjectablesDependenciesRef(name?: string) {
25 | return DEPENDENCIES
26 | .filter(dep => dep['inject'] && dep['inject'] === (name || true))
27 | .map(mapPath);
28 | }
29 |
30 | function mapPath(dep) {
31 | let prodPath = join(dep.dest, dep.src.split(sep).pop());
32 | return ('prod' === ENV ? prodPath : dep.src );
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/tools/tasks/build.js.dev.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC, APP_DEST} from '../config';
3 | import {templateLocals, tsProjectFn} from '../utils';
4 |
5 | export = function buildJSDev(gulp, plugins) {
6 | let tsProject = tsProjectFn(plugins);
7 | return function () {
8 | let src = [
9 | join(APP_SRC, '**/*.ts'),
10 | '!' + join(APP_SRC, '**/*_spec.ts')
11 | ];
12 |
13 | let result = gulp.src(src)
14 | .pipe(plugins.plumber())
15 | // Won't be required for non-production build after the change
16 | .pipe(plugins.inlineNg2Template({ base: APP_SRC }))
17 | .pipe(plugins.sourcemaps.init())
18 | .pipe(plugins.typescript(tsProject));
19 |
20 | return result.js
21 | .pipe(plugins.sourcemaps.write())
22 | .pipe(plugins.template(templateLocals()))
23 | .pipe(gulp.dest(APP_DEST));
24 | };
25 | };
26 |
--------------------------------------------------------------------------------
/tools/tasks/build.js.prod.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC, TMP_DIR} from '../config';
3 | import {templateLocals, tsProjectFn} from '../utils';
4 |
5 | export = function buildJSDev(gulp, plugins) {
6 | return function () {
7 | let tsProject = tsProjectFn(plugins);
8 | let src = [
9 | join(APP_SRC, '**/*.ts'),
10 | '!' + join(APP_SRC, '**/*_spec.ts')
11 | ];
12 |
13 | let result = gulp.src(src)
14 | .pipe(plugins.plumber())
15 | .pipe(plugins.inlineNg2Template({ base: TMP_DIR }))
16 | .pipe(plugins.typescript(tsProject));
17 |
18 | return result.js
19 | .pipe(plugins.template(templateLocals()))
20 | .pipe(gulp.dest(TMP_DIR));
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/tools/tasks/build.sass.dev.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC} from '../config';
3 |
4 | export = function buildSassDev(gulp, plugins, option) {
5 | return function () {
6 | return gulp.src(join(APP_SRC, '**', '*.scss'))
7 | .pipe(plugins.sass().on('error', plugins.sass.logError))
8 | .pipe(gulp.dest(APP_SRC));
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/tools/tasks/build.test.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC, TEST_DEST} from '../config';
3 | import {tsProjectFn} from '../utils';
4 |
5 | export = function buildTest(gulp, plugins) {
6 | return function () {
7 | let tsProject = tsProjectFn(plugins);
8 | let src = [
9 | join(APP_SRC, '**/*.ts'),
10 | '!' + join(APP_SRC, 'bootstrap.ts')
11 | ];
12 |
13 | let result = gulp.src(src)
14 | .pipe(plugins.plumber())
15 | .pipe(plugins.inlineNg2Template({ base: APP_SRC }))
16 | .pipe(plugins.typescript(tsProject));
17 |
18 | return result.js
19 | .pipe(gulp.dest(TEST_DEST));
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/tools/tasks/check.versions.ts:
--------------------------------------------------------------------------------
1 | import {VERSION_NPM, VERSION_NODE} from '../config';
2 |
3 | function reportError(message: string) {
4 | console.error(require('chalk').white.bgRed.bold(message));
5 | process.exit(1);
6 | }
7 |
8 | module.exports = function check(gulp, plugins) {
9 | return function () {
10 | let exec = require('child_process').exec;
11 | let semver = require('semver');
12 |
13 | exec('npm --version',
14 | function (error, stdout, stderr) {
15 | if (error !== null) {
16 | reportError('npm preinstall error: ' + error + stderr);
17 | }
18 |
19 | if (!semver.gte(stdout, VERSION_NPM)) {
20 | reportError('NPM is not in required version! Required is ' + VERSION_NPM + ' and you\'re using ' + stdout);
21 | }
22 | });
23 |
24 | exec('node --version',
25 | function (error, stdout, stderr) {
26 | if (error !== null) {
27 | reportError('npm preinstall error: ' + error + stderr);
28 | }
29 |
30 | if (!semver.gte(stdout, VERSION_NODE)) {
31 | reportError('NODE is not in required version! Required is ' + VERSION_NODE + ' and you\'re using ' + stdout);
32 | }
33 | });
34 | };
35 | };
36 |
--------------------------------------------------------------------------------
/tools/tasks/clean.ts:
--------------------------------------------------------------------------------
1 | import * as async from 'async';
2 | import * as del from 'del';
3 | import {APP_DEST, TEST_DEST, TMP_DIR} from '../config';
4 |
5 | export = function clean(gulp, plugins, option) {
6 | return function (done) {
7 |
8 | switch(option) {
9 | case 'all' : cleanAll(done); break;
10 | case 'dist' : cleanDist(done); break;
11 | case 'test' : cleanTest(done); break;
12 | case 'tmp' : cleanTmp(done); break;
13 | default: done();
14 | }
15 |
16 | };
17 | };
18 |
19 | function cleanAll(done) {
20 | async.parallel([
21 | cleanDist,
22 | cleanTest,
23 | cleanTmp
24 | ], done);
25 | }
26 | function cleanDist(done) {
27 | del(APP_DEST, done);
28 | }
29 | function cleanTest(done) {
30 | del(TEST_DEST, done);
31 | }
32 | function cleanTmp(done) {
33 | del(TMP_DIR, done);
34 | }
35 |
--------------------------------------------------------------------------------
/tools/tasks/karma.start.ts:
--------------------------------------------------------------------------------
1 | import * as karma from 'karma';
2 | import {join} from 'path';
3 |
4 | export = function karmaStart() {
5 | return function (done) {
6 | new (karma).Server({
7 | configFile: join(process.cwd(), 'karma.conf.js'),
8 | singleRun: true
9 | }).start(done);
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/tools/tasks/npm.ts:
--------------------------------------------------------------------------------
1 | export = function npm(gulp, plugins) {
2 | return plugins.shell.task([
3 | 'npm prune'
4 | ]);
5 | };
6 |
--------------------------------------------------------------------------------
/tools/tasks/serve.docs.ts:
--------------------------------------------------------------------------------
1 | import {serveDocs} from '../utils';
2 |
3 | export = function serverStart(gulp, plugins) {
4 | return function () {
5 | serveDocs();
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/tools/tasks/server.start.ts:
--------------------------------------------------------------------------------
1 | import {serveSPA} from '../utils';
2 |
3 | export = function serverStart(gulp, plugins) {
4 | return function () {
5 | serveSPA();
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/tools/tasks/tsd.ts:
--------------------------------------------------------------------------------
1 | export = function tsd(gulp, plugins) {
2 | return plugins.shell.task([
3 | 'tsd reinstall --clean',
4 | 'tsd link',
5 | 'tsd rebundle'
6 | ]);
7 | };
8 |
--------------------------------------------------------------------------------
/tools/tasks/tslint.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC, TOOLS_DIR} from '../config';
3 |
4 | export = function tslint(gulp, plugins) {
5 | return function () {
6 | let src = [
7 | join(APP_SRC, '**/*.ts'),
8 | '!' + join(APP_SRC, '**/*.d.ts'),
9 | join(TOOLS_DIR, '**/*.ts'),
10 | '!' + join(TOOLS_DIR, '**/*.d.ts')
11 | ];
12 |
13 | return gulp.src(src)
14 | .pipe(plugins.tslint())
15 | .pipe(plugins.tslint.report(plugins.tslintStylish, {
16 | emitError: false,
17 | sort: true,
18 | bell: true
19 | }));
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/tools/tasks/watch.dev.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC} from '../config';
3 |
4 | export = function watchDev(gulp, plugins) {
5 | return function () {
6 | plugins.watch(join(APP_SRC, '**/*'), () => gulp.start('build.dev'));
7 | };
8 | };
9 |
--------------------------------------------------------------------------------
/tools/tasks/watch.serve.ts:
--------------------------------------------------------------------------------
1 | import * as runSequence from 'run-sequence';
2 | import {join} from 'path';
3 | import {APP_SRC} from '../config';
4 | import {notifyLiveReload} from '../utils';
5 |
6 | export = function watchServe(gulp, plugins) {
7 | return function () {
8 | plugins.watch(join(APP_SRC, '**'), e =>
9 | runSequence('build.dev', () => notifyLiveReload(e))
10 | );
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/tools/tasks/watch.test.ts:
--------------------------------------------------------------------------------
1 | import {join} from 'path';
2 | import {APP_SRC} from '../config';
3 |
4 | export = function watchTest(gulp, plugins) {
5 | return function () {
6 | plugins.watch(join(APP_SRC, '**/*.ts'), () => gulp.start('build.test'));
7 | };
8 | };
9 |
--------------------------------------------------------------------------------
/tools/typings/connect-livereload.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'connect-livereload' {
2 | function connectLivereload(options?: any): any;
3 | module connectLivereload {}
4 | export = connectLivereload;
5 | }
6 |
--------------------------------------------------------------------------------
/tools/typings/gulp-load-plugins.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for gulp-load-plugins
2 | // Project: https://github.com/jackfranklin/gulp-load-plugins
3 | // Definitions by: Joe Skeen
4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped
5 |
6 | // Does not support ES2015 import (import * as open from 'open').
7 |
8 | /** Loads in any gulp plugins and attaches them to an object, freeing you up from having to manually require each gulp plugin. */
9 | declare module 'gulp-load-plugins' {
10 |
11 | interface IOptions {
12 | /** the glob(s) to search for, default ['gulp-*', 'gulp.*'] */
13 | pattern?: string[];
14 | /** where to find the plugins, searched up from process.cwd(), default 'package.json' */
15 | config?: string;
16 | /** which keys in the config to look within, default ['dependencies', 'devDependencies', 'peerDependencies'] */
17 | scope?: string[];
18 | /** what to remove from the name of the module when adding it to the context, default /^gulp(-|\.)/ */
19 | replaceString?: RegExp;
20 | /** if true, transforms hyphenated plugin names to camel case, default true */
21 | camelize?: boolean;
22 | /** whether the plugins should be lazy loaded on demand, default true */
23 | lazy?: boolean;
24 | /** a mapping of plugins to rename, the key being the NPM name of the package, and the value being an alias you define */
25 | rename?: IPluginNameMappings;
26 | }
27 |
28 | interface IPluginNameMappings {
29 | [npmPackageName: string]: string;
30 | }
31 |
32 | /** Loads in any gulp plugins and attaches them to an object, freeing you up from having to manually require each gulp plugin. */
33 | function gulpLoadPlugins(options?: IOptions): T;
34 | module gulpLoadPlugins {}
35 | export = gulpLoadPlugins;
36 | }
37 |
38 | /**
39 | * Extend this interface to use Gulp plugins in your gulpfile.js
40 | */
41 | interface IGulpPlugins {
42 | }
43 |
--------------------------------------------------------------------------------
/tools/typings/karma.d.ts:
--------------------------------------------------------------------------------
1 | // Use this minimalistic definition file as bluebird dependency
2 | // generate a lot of errors.
3 |
4 | declare module 'karma' {
5 | var karma: IKarma;
6 | export = karma;
7 | interface IKarma {
8 | server: {
9 | start(options: any, callback: Function): void
10 | };
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/tools/typings/merge-stream.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'merge-stream' {
2 | function mergeStream(...streams: NodeJS.ReadWriteStream[]): MergeStream;
3 | interface MergeStream extends NodeJS.ReadWriteStream {
4 | add(stream: NodeJS.ReadWriteStream): MergeStream;
5 | }
6 | module mergeStream {}
7 | export = mergeStream;
8 | }
--------------------------------------------------------------------------------
/tools/typings/open.d.ts:
--------------------------------------------------------------------------------
1 | // https://github.com/borisyankov/DefinitelyTyped/tree/master/open
2 | // Does not support ES2015 import (import * as open from 'open').
3 |
4 | declare module 'open' {
5 | function open(target: string, app?: string): void;
6 | module open {}
7 | export = open;
8 | }
9 |
--------------------------------------------------------------------------------
/tools/typings/run-sequence.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'run-sequence' {
2 | function runSequence(...args: any[]): void;
3 | module runSequence {}
4 | export = runSequence;
5 | }
6 |
--------------------------------------------------------------------------------
/tools/typings/slash.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'slash' {
2 | function slash(path: string): string;
3 | module slash {}
4 | export = slash;
5 | }
6 |
--------------------------------------------------------------------------------
/tools/typings/systemjs-builder.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'systemjs-builder' {
2 | class Builder {
3 | constructor(configObject?: any, baseUrl?: string, configPath?: string);
4 | bundle(source: string, target: string, options?: any): Promise;
5 | buildStatic(source: string, target: string, options?: any): Promise;
6 | }
7 |
8 | module Builder {}
9 | export = Builder;
10 | }
11 |
--------------------------------------------------------------------------------
/tools/typings/tiny-lr.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'tiny-lr' {
2 | function tinylr(): ITinylr;
3 | module tinylr {}
4 | export = tinylr;
5 |
6 | interface ITinylr {
7 | changed(options: any): void;
8 | listen(port: number): void;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tools/typings/yargs.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'yargs' {
2 | var yargs: IYargs;
3 | export = yargs;
4 |
5 | // Minimalistic but serves the usage in the seed.
6 | interface IYargs {
7 | argv: any;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tools/utils.ts:
--------------------------------------------------------------------------------
1 | export * from './utils/template-injectables';
2 | export * from './utils/template-locals';
3 | export * from './utils/server';
4 | export * from './utils/tasks_tools';
5 |
6 |
7 | export function tsProjectFn(plugins) {
8 | return plugins.typescript.createProject('tsconfig.json', {
9 | typescript: require('typescript')
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/tools/utils/server.ts:
--------------------------------------------------------------------------------
1 | import * as connectLivereload from 'connect-livereload';
2 | import * as express from 'express';
3 | import * as tinylrFn from 'tiny-lr';
4 | import * as openResource from 'open';
5 | import * as serveStatic from 'serve-static';
6 | import {resolve} from 'path';
7 | import {APP_BASE, APP_DEST, DOCS_DEST, LIVE_RELOAD_PORT, DOCS_PORT, PORT} from '../config';
8 |
9 | let tinylr = tinylrFn();
10 |
11 |
12 | export function serveSPA() {
13 | let server = express();
14 | tinylr.listen(LIVE_RELOAD_PORT);
15 |
16 | server.use(
17 | APP_BASE,
18 | connectLivereload({ port: LIVE_RELOAD_PORT }),
19 | express.static(process.cwd())
20 | );
21 |
22 | server.listen(PORT, () =>
23 | openResource('http://localhost:' + PORT + APP_BASE + APP_DEST)
24 | );
25 | }
26 |
27 | export function notifyLiveReload(e) {
28 | let fileName = e.path;
29 | tinylr.changed({
30 | body: { files: [fileName] }
31 | });
32 | }
33 |
34 | export function serveDocs() {
35 | let server = express();
36 |
37 | server.use(
38 | APP_BASE,
39 | serveStatic(resolve(process.cwd(), DOCS_DEST))
40 | );
41 |
42 | server.listen(DOCS_PORT, () =>
43 | openResource('http://localhost:' + DOCS_PORT + APP_BASE)
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/tools/utils/tasks_tools.ts:
--------------------------------------------------------------------------------
1 | import * as gulp from 'gulp';
2 | import * as util from 'gulp-util';
3 | import * as chalk from 'chalk';
4 | import * as gulpLoadPlugins from 'gulp-load-plugins';
5 | import * as _runSequence from 'run-sequence';
6 | import {readdirSync, existsSync, lstatSync} from 'fs';
7 | import {join} from 'path';
8 | import {TOOLS_DIR} from '../config';
9 |
10 | const TASKS_PATH = join(TOOLS_DIR, 'tasks');
11 |
12 | // NOTE: Remove if no issues with runSequence function below.
13 | // export function loadTasks(): void {
14 | // scanDir(TASKS_PATH, (taskname) => registerTask(taskname));
15 | // }
16 |
17 | export function task(taskname: string, option?: string) {
18 | util.log('Loading task', chalk.yellow(taskname, option || ''));
19 | return require(join('..', 'tasks', taskname))(gulp, gulpLoadPlugins(), option);
20 | }
21 |
22 | export function runSequence(...sequence: any[]) {
23 | let tasks = [];
24 | let _sequence = sequence.slice(0);
25 | sequence.pop();
26 |
27 | scanDir(TASKS_PATH, taskname => tasks.push(taskname));
28 |
29 | sequence.forEach(task => {
30 | if (tasks.indexOf(task) > -1) { registerTask(task); }
31 | });
32 |
33 | return _runSequence(..._sequence);
34 | }
35 |
36 | // ----------
37 | // Private.
38 |
39 | function registerTask(taskname: string, filename?: string, option: string = ''): void {
40 | gulp.task(taskname, task(filename || taskname, option));
41 | }
42 |
43 | // TODO: add recursive lookup ? or enforce pattern file + folder (ie ./tools/utils & ./tools/utils.ts )
44 | function scanDir(root: string, cb: (taskname: string) => void) {
45 | if (!existsSync(root)) return;
46 |
47 | walk(root);
48 |
49 | function walk(path) {
50 | let files = readdirSync(path);
51 | for (let i = 0; i < files.length; i += 1) {
52 | let file = files[i];
53 | let curPath = join(path, file);
54 | // if (lstatSync(curPath).isDirectory()) { // recurse
55 | // path = file;
56 | // walk(curPath);
57 | // }
58 | if (lstatSync(curPath).isFile() && /\.ts$/.test(file)) {
59 | let taskname = file.replace(/(\.ts)/, '');
60 | cb(taskname);
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tools/utils/template-injectables.ts:
--------------------------------------------------------------------------------
1 | import * as slash from 'slash';
2 | import {join} from 'path';
3 | import {APP_BASE, APP_DEST, ENV} from '../config';
4 |
5 | let injectables: string[] = [];
6 |
7 | export function injectableAssetsRef() {
8 | return injectables;
9 | }
10 |
11 | export function registerInjectableAssetsRef(paths: string[], target: string = '') {
12 | injectables = injectables.concat(
13 | paths
14 | .filter(path => !/(\.map)$/.test(path))
15 | .map(path => join(target, slash(path).split('/').pop()))
16 | );
17 | }
18 |
19 | export function transformPath(plugins, env) {
20 | return function (filepath) {
21 | filepath = ENV === 'prod' ? filepath.replace(`/${APP_DEST}`, '') : filepath;
22 | arguments[0] = join(APP_BASE, filepath);
23 | return slash(plugins.inject.transform.apply(plugins.inject.transform, arguments));
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/tools/utils/template-locals.ts:
--------------------------------------------------------------------------------
1 | import {APP_BASE, APP_DEST, APP_ROOT, APP_TITLE, SYSTEM_CONFIG, VERSION} from '../config';
2 |
3 | // TODO: Add an interface to register more template locals.
4 | export function templateLocals() {
5 | return {
6 | APP_BASE,
7 | APP_DEST,
8 | APP_ROOT,
9 | APP_TITLE,
10 | SYSTEM_CONFIG,
11 | VERSION
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "declaration": false,
6 | "noImplicitAny": false,
7 | "removeComments": true,
8 | "noLib": false,
9 | "emitDecoratorMetadata": true,
10 | "experimentalDecorators": true,
11 | "sourceMap": true
12 | },
13 | "exclude": [
14 | "node_modules"
15 | ],
16 | "compileOnSave": false
17 | }
18 |
--------------------------------------------------------------------------------
/tsd.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v4",
3 | "repo": "DefinitelyTyped/DefinitelyTyped",
4 | "ref": "master",
5 | "path": "tools/typings/tsd",
6 | "bundle": "tools/typings/tsd/tsd.d.ts",
7 | "installed": {
8 | "systemjs/systemjs.d.ts": {
9 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
10 | },
11 | "gulp/gulp.d.ts": {
12 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
13 | },
14 | "q/Q.d.ts": {
15 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
16 | },
17 | "orchestrator/orchestrator.d.ts": {
18 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
19 | },
20 | "gulp-shell/gulp-shell.d.ts": {
21 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
22 | },
23 | "mime/mime.d.ts": {
24 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
25 | },
26 | "express/express.d.ts": {
27 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
28 | },
29 | "serve-static/serve-static.d.ts": {
30 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
31 | },
32 | "del/del.d.ts": {
33 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
34 | },
35 | "glob/glob.d.ts": {
36 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
37 | },
38 | "minimatch/minimatch.d.ts": {
39 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
40 | },
41 | "async/async.d.ts": {
42 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f"
43 | },
44 | "es6-promise/es6-promise.d.ts": {
45 | "commit": "923c5431d9447db9d5cf41adc5914e3c94c1ff10"
46 | },
47 | "node/node.d.ts": {
48 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff"
49 | },
50 | "gulp-util/gulp-util.d.ts": {
51 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff"
52 | },
53 | "vinyl/vinyl.d.ts": {
54 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff"
55 | },
56 | "through2/through2.d.ts": {
57 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff"
58 | },
59 | "chalk/chalk.d.ts": {
60 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff"
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "class-name": true,
4 | "curly": false,
5 | "eofline": true,
6 | "indent": "spaces",
7 | "max-line-length": [true, 140],
8 | "member-ordering": [true,
9 | "public-before-private",
10 | "static-before-instance",
11 | "variables-before-functions"
12 | ],
13 | "no-arg": true,
14 | "no-construct": true,
15 | "no-duplicate-key": true,
16 | "no-duplicate-variable": true,
17 | "no-empty": true,
18 | "no-eval": true,
19 | "no-trailing-comma": true,
20 | "no-trailing-whitespace": true,
21 | "no-unused-expression": true,
22 | "no-unused-variable": true,
23 | "no-unreachable": true,
24 | "no-use-before-declare": true,
25 | "one-line": [true,
26 | "check-open-brace",
27 | "check-catch",
28 | "check-else",
29 | "check-whitespace"
30 | ],
31 | "quotemark": [true, "single"],
32 | "semicolon": true,
33 | "triple-equals": true,
34 | "variable-name": false
35 | }
36 | }
37 |
--------------------------------------------------------------------------------