Initial commit.

This commit is contained in:
smartapant 2016-04-20 16:32:12 +03:00
commit 6558ee2fc4
92 changed files with 3193 additions and 0 deletions

View file

@ -0,0 +1,55 @@
import {Component} from 'angular2/core';
/*
* We're loading this component asynchronously
* We are using some magic with es6-promise-loader that will wrap the module with a Promise
* see https://github.com/gdi2290/es6-promise-loader for more info
*/
console.log('`About` component loaded asynchronously');
@Component({
selector: 'about',
styles: [`
h1 {
font-family: Arial, Helvetica, sans-serif
}
`],
template: `
<md-card>
<h1>
patrick@AngularClass.com
</h1>
</md-card>
`
})
export class About {
constructor() {
}
ngOnInit() {
console.log('hello `About` component');
// static data that is bundled
// var mockData = require('assets/mock-data/mock-data.json');
// console.log('mockData', mockData);
// if you're working with mock data you can also use http.get('assets/mock-data/mock-data.json')
// this.asyncDataWithWebpack();
}
asyncDataWithWebpack() {
// you can also async load mock data with 'es6-promise-loader'
// you would do this if you don't want the mock-data bundled
// remember that 'es6-promise-loader' is a promise
// var asyncMockDataPromiseFactory = require('es6-promise!assets/mock-data/mock-data.json');
// setTimeout(() => {
//
// let asyncDataPromise = asyncMockDataPromiseFactory();
// asyncDataPromise.then(json => {
// console.log('async mockData', json);
// });
//
// });
}
}

View file

@ -0,0 +1,29 @@
import {
it,
inject,
injectAsync,
describe,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import {Component, provide} from 'angular2/core';
// Load the implementations that should be tested
import {About} from './about.component';
describe('About', () => {
// provide our implementations or mocks to the dependency injector
beforeEachProviders(() => [
About
]);
it('should log ngOnInit', inject([ About ], (about) => {
spyOn(console, 'log');
expect(console.log).not.toHaveBeenCalled();
about.ngOnInit();
expect(console.log).toHaveBeenCalled();
}));
});

1
src/app/about/index.ts Normal file
View file

@ -0,0 +1 @@
export * from './about.component';

99
src/app/app.component.ts Normal file
View file

@ -0,0 +1,99 @@
/*
* Angular 2 decorators and services
*/
import {Component, ViewEncapsulation} from 'angular2/core';
import {RouteConfig, Router} from 'angular2/router';
import {Home} from './home';
import {AppState} from './app.service';
import {RouterActive} from './router-active';
/*
* App Component
* Top Level Component
*/
@Component({
selector: 'app',
pipes: [ ],
providers: [ ],
directives: [ RouterActive ],
encapsulation: ViewEncapsulation.None,
styles: [
require('normalize.css'),
`
md-toolbar ul {
display: inline;
list-style-type: none;
margin: 0;
padding: 0;
width: 60px;
}
md-toolbar li {
display: inline;
}
md-toolbar li.active {
background-color: lightgray;
}
`],
template: `
<header>
<md-toolbar color="primary">
<span>{{ name }}</span>
<nav>
<ul>
<li router-active>
<a [routerLink]=" ['Index'] ">Index</a>
</li>
|
<li router-active>
<a [routerLink]=" ['Home'] ">Home</a>
</li>
|
<li router-active>
<a [routerLink]=" ['About'] ">About</a>
</li>
</ul>
</nav>
</md-toolbar>
</header>
<main>
<router-outlet></router-outlet>
</main>
<pre>this.appState.state = {{ appState.state | json }}</pre>
<footer>
WebPack Angular 2 Starter by <a [href]="url">@AngularClass</a>
<div>
<img [src]="angularclassLogo" width="10%">
</div>
</footer>
`
})
@RouteConfig([
{ path: '/', name: 'Index', component: Home, useAsDefault: true },
{ path: '/home', name: 'Home', component: Home },
// Async load a component using Webpack's require with es6-promise-loader and webpack `require`
{ path: '/about', name: 'About', loader: () => require('es6-promise!./about')('About') }
])
export class App {
angularclassLogo = 'assets/img/angularclass-avatar.png';
name = 'Angular 2 Webpack Starter';
url = 'https://twitter.com/AngularClass';
constructor(public appState: AppState) {}
ngOnInit() {
console.log('Initial App State', this.appState.state);
}
}
/*
* Please review the https://github.com/AngularClass/angular2-examples/ repo for
* more angular app examples that you may copy/paste
* (The examples may not be updated as quickly. Please open an issue on github for us to update it)
* For help or questions please contact us at @AngularClass on twitter
* or our chat on Slack at https://AngularClass.com/slack-join
*/

32
src/app/app.e2e.ts Normal file
View file

@ -0,0 +1,32 @@
describe('App', () => {
beforeEach(() => {
browser.get('/');
});
it('should have a title', () => {
let subject = browser.getTitle();
let result = 'Angular2 Webpack Starter by @gdi2290 from @AngularClass';
expect(subject).toEqual(result);
});
it('should have <header>', () => {
let subject = element(by.css('app header')).isPresent();
let result = true;
expect(subject).toEqual(result);
});
it('should have <main>', () => {
let subject = element(by.css('app main')).isPresent();
let result = true;
expect(subject).toEqual(result);
});
it('should have <footer>', () => {
let subject = element(by.css('app footer')).getText();
let result = 'WebPack Angular 2 Starter by @AngularClass';
expect(subject).toEqual(result);
});
});

39
src/app/app.service.ts Normal file
View file

@ -0,0 +1,39 @@
import {Injectable} from 'angular2/core';
import {HmrState} from 'angular2-hmr';
@Injectable()
export class AppState {
// HmrState uis used by HMR to track the any state during reloading
@HmrState() _state = {};
constructor() {
}
// already return a clone of the current state
get state() {
return this._state = this._clone(this._state);
}
// never allow mutation
set state(value) {
throw new Error('do not mutate the `.state` directly');
}
get(prop?: any) {
// use our state getter for the clone
const state = this.state;
return state[prop] || state;
}
set(prop: string, value: any) {
// internally mutate our state
return this._state[prop] = value;
}
_clone(object) {
// simple object clone
return JSON.parse(JSON.stringify( object ));
}
}

24
src/app/app.spec.ts Normal file
View file

@ -0,0 +1,24 @@
import {
it,
inject,
injectAsync,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
// Load the implementations that should be tested
import {App} from './app.component';
import {AppState} from './app.service';
describe('App', () => {
// provide our implementations or mocks to the dependency injector
beforeEachProviders(() => [
AppState,
App
]);
it('should have a url', inject([ App ], (app) => {
expect(app.url).toEqual('https://twitter.com/AngularClass');
}));
});

View file

@ -0,0 +1,46 @@
import {Component} from 'angular2/core';
import {AppState} from '../app.service';
import {Title} from './title';
import {XLarge} from './x-large';
@Component({
// The selector is what angular internally uses
// for `document.querySelectorAll(selector)` in our index.html
// where, in this case, selector is the string 'home'
selector: 'home', // <home></home>
// We need to tell Angular's Dependency Injection which providers are in our app.
providers: [
Title
],
// We need to tell Angular's compiler which directives are in our template.
// Doing so will allow Angular to attach our behavior to an element
directives: [
XLarge
],
// We need to tell Angular's compiler which custom pipes are in our template.
pipes: [ ],
// Our list of styles in our component. We may add more to compose many styles together
styles: [ require('./home.css') ],
// Every Angular template is first compiled by the browser before Angular runs it's compiler
template: require('./home.html')
})
export class Home {
// Set our default values
localState = { value: '' };
// TypeScript public modifiers
constructor(public appState: AppState, public title: Title) {
}
ngOnInit() {
console.log('hello `Home` component');
// this.title.getData().subscribe(data => this.data = data);
}
submitState(value) {
console.log('submitState', value);
this.appState.set('value', value);
}
}

0
src/app/home/home.css Normal file
View file

22
src/app/home/home.e2e.ts Normal file
View file

@ -0,0 +1,22 @@
describe('App', () => {
beforeEach(() => {
// change hash depending on router LocationStrategy
browser.get('/#/home');
});
it('should have a title', () => {
let subject = browser.getTitle();
let result = 'Angular2 Webpack Starter by @gdi2290 from @AngularClass';
expect(subject).toEqual(result);
});
it('should have `your content here` x-large', () => {
let subject = element(by.css('[x-large]')).getText();
let result = 'Your Content Here';
expect(subject).toEqual(result);
});
});

31
src/app/home/home.html Normal file
View file

@ -0,0 +1,31 @@
<md-card>
<md-card-content>
<span x-large>Your Content Here</span>
<form (ngSubmit)="submitState(localState.value)" autocomplete="off">
<md-input
placeholder="Submit Local State to App State"
[value]="localState.value"
(input)="localState.value = $event.target.value"
autofocus>
</md-input>
<button md-raised-button color="primary">Submit Value</button>
</form>
<!--
<input type="text" [value]="localState.value" (input)="localState.value = $event.target.value" autofocus>
Rather than wiring up two-way data-binding ourselves with [value] and (input)
we can use Angular's [(ngModel)] syntax
<input type="text" [(ngModel)]="localState.value" autofocus>
-->
<md-card>
For hot module reloading run
<pre>npm run start:hmr</pre>
</md-card>
<hr>
<pre>this.localState = {{ localState | json }}</pre>
</md-card-content>
</md-card>

52
src/app/home/home.spec.ts Normal file
View file

@ -0,0 +1,52 @@
import {
it,
inject,
injectAsync,
describe,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import {Component, provide} from 'angular2/core';
import {BaseRequestOptions, Http} from 'angular2/http';
import {MockBackend} from 'angular2/http/testing';
// Load the implementations that should be tested
import {Home} from './home.component';
import {Title} from './title';
import {AppState} from '../app.service';
describe('Home', () => {
// provide our implementations or mocks to the dependency injector
beforeEachProviders(() => [
BaseRequestOptions,
MockBackend,
provide(Http, {
useFactory: function(backend, defaultOptions) {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
}),
AppState,
Title,
Home
]);
it('should have default data', inject([ Home ], (home) => {
expect(home.localState).toEqual({ value: '' });
}));
it('should have a title', inject([ Home ], (home) => {
expect(!!home.title).toEqual(true);
}));
it('should log ngOnInit', inject([ Home ], (home) => {
spyOn(console, 'log');
expect(console.log).not.toHaveBeenCalled();
home.ngOnInit();
expect(console.log).toHaveBeenCalled();
}));
});

1
src/app/home/index.ts Normal file
View file

@ -0,0 +1 @@
export * from './home.component';

View file

@ -0,0 +1 @@
export * from './title.service';

View file

@ -0,0 +1,20 @@
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
@Injectable()
export class Title {
value = 'Angular 2';
constructor(public http: Http) {
}
getData() {
console.log('Title#getData(): Get Data');
// return this.http.get('/assets/data.json')
// .map(res => res.json());
return {
value: 'AngularClass'
};
}
}

View file

@ -0,0 +1,44 @@
import {
it,
inject,
injectAsync,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import {Component, provide} from 'angular2/core';
import {BaseRequestOptions, Http} from 'angular2/http';
import {MockBackend} from 'angular2/http/testing';
import {Title} from './title.service';
describe('Title', () => {
beforeEachProviders(() => [
BaseRequestOptions,
MockBackend,
provide(Http, {
useFactory: function(backend, defaultOptions) {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
}),
Title
]);
it('should have http', inject([ Title ], (title) => {
expect(!!title.http).toEqual(true);
}));
it('should get data from the server', inject([ Title ], (title) => {
spyOn(console, 'log');
expect(console.log).not.toHaveBeenCalled();
title.getData();
expect(console.log).toHaveBeenCalled();
expect(title.getData()).toEqual({ value: 'AngularClass' });
}));
});

View file

@ -0,0 +1 @@
export * from './x-large.directive';

View file

@ -0,0 +1,18 @@
import {Directive, Component, ElementRef, Renderer} from 'angular2/core';
/*
* Directive
* XLarge is a simple directive to show how one is made
*/
@Directive({
selector: '[x-large]' // using [ ] means selecting attributes
})
export class XLarge {
constructor(element: ElementRef, renderer: Renderer) {
// simple DOM manipulation to set font size to x-large
// `nativeElement` is the direct reference to the DOM element
// element.nativeElement.style.fontSize = 'x-large';
// for server/webworker support use the renderer
renderer.setElementStyle(element.nativeElement, 'fontSize', 'x-large');
}
}

View file

@ -0,0 +1,34 @@
import {
it,
inject,
injectAsync,
describe,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import {Component, provide} from 'angular2/core';
import {BaseRequestOptions, Http} from 'angular2/http';
import {MockBackend} from 'angular2/http/testing';
// Load the implementations that should be tested
import {XLarge} from './x-large.directive';
describe('x-large directive', () => {
// Create a test component to test directives
@Component({
template: '',
directives: [ XLarge ]
})
class TestComponent {}
it('should sent font-size to x-large', injectAsync([TestComponentBuilder], (tcb) => {
return tcb.overrideTemplate(TestComponent, '<div x-large>Content</div>')
.createAsync(TestComponent).then((fixture: any) => {
fixture.detectChanges();
let compiled = fixture.debugElement.nativeElement.children[0];
expect(compiled.style.fontSize).toBe('x-large');
});
}));
});

10
src/app/index.ts Normal file
View file

@ -0,0 +1,10 @@
// App
export * from './app.component';
export * from './app.service';
import {AppState} from './app.service';
// Application wide providers
export const APP_PROVIDERS = [
AppState
];

View file

@ -0,0 +1,2 @@
// Application level directive
export * from './router-active.directive';

View file

@ -0,0 +1,73 @@
import {Router} from 'angular2/router';
import {isPresent} from 'angular2/src/facade/lang';
import {
Directive,
Query,
QueryList,
Attribute,
ElementRef,
Renderer,
Optional,
Input
} from 'angular2/core';
import {Instruction, RouterLink} from 'angular2/router';
/**
* RouterActive dynamically finds the first element with routerLink and toggles the active class
*
* ## Use
*
* ```
* <li router-active="active"><a [routerLink]=" ['/Home'] ">Home</a></li>
* <li [routerActive]=" activeStringValue "><a [routerLink]=" ['/Home'] ">Home</a></li>
* ```
*/
@Directive({
selector: '[router-active]'
})
export class RouterActive {
@Input() routerActive: string = undefined;
routerActiveAttr: string = 'active';
constructor(
public router: Router,
public element: ElementRef,
public renderer: Renderer,
@Query(RouterLink) public routerLink: QueryList<RouterLink>,
@Optional() @Attribute('router-active') routerActiveAttr?: string) {
this.routerActiveAttr = this._defaultAttrValue(routerActiveAttr);
}
ngOnInit() {
this.routerLink.changes.subscribe(() => {
if (this.routerLink.first) {
this._updateClass();
this._findRootRouter().subscribe(() => {
this._updateClass();
});
}
});
}
private _findRootRouter(): Router {
let router: Router = this.router;
while (isPresent(router.parent)) {
router = router.parent;
}
return router;
}
private _updateClass() {
let active = this.routerLink.first.isRouteActive;
this.renderer.setElementClass(this.element.nativeElement, this._attrOrProp(), active);
}
private _defaultAttrValue(attr?: string) {
return this.routerActiveAttr = attr || this.routerActiveAttr;
}
private _attrOrProp() {
return isPresent(this.routerActive) ? this.routerActive : this.routerActiveAttr;
}
}