dependency upgrades, server and platform module updates, linting wip

This commit is contained in:
William Welling
2017-07-12 14:33:16 -05:00
parent afc39022f8
commit c08f5c672b
190 changed files with 6321 additions and 4703 deletions

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { Cookies } from './cookies';
import { BrowserCookies } from './browser-cookies';
@NgModule({
providers: [
{ provide: Cookies, useClass: BrowserCookies }
]
})
export class BrowserCookiesModule {
}

View File

@@ -0,0 +1,34 @@
import { Injectable } from '@angular/core';
import { Cookies } from './cookies';
@Injectable()
export class BrowserCookies implements Cookies {
// TODO: improve - set domain from configuration value or ui baseUrl
set(name: string, value: string, days: number, path?: string): void {
const date: Date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
const expires: string = 'expires=' + date.toUTCString();
window.document.cookie = [name, '=', value, '; ', expires, path ? '; path=' + path : ''].join('');
}
get(name: string): string {
const cookies: string[] = window.document.cookie.split(';');
let cookie: string;
for (const cc of cookies) {
const c: string = cc.replace(/^\s\+/g, '');
if (c.indexOf(name + '=') === 0) {
cookie = c.substring(name.length + 1, c.length);
break;
}
}
return cookie;
}
// TODO: set path from environment configuration
remove(name: string): void {
this.set(name, '', 0, '/');
}
}

View File

@@ -0,0 +1,9 @@
export abstract class Cookies {
abstract set(name: string, value: string, days: number, path?: string): void;
abstract get(name: string): string;
abstract remove(name: string): void;
}

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { Cookies } from './cookies';
import { ServerCookies } from './server-cookies';
@NgModule({
providers: [
{ provide: Cookies, useClass: ServerCookies }
]
})
export class ServerCookiesModule {
}

View File

@@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
import { Cookies } from './cookies';
@Injectable()
export class ServerCookies implements Cookies {
// tslint:disable:no-empty
set(name: string, value: string, days: number, path?: string): void {
}
// tslint:enable:no-empty
get(name: string): string {
return undefined;
}
// tslint:disable:no-empty
remove(name: string): void {
}
// tslint:enable:no-empty
}

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { DataLoader } from './data-loader';
import { BrowserDataLoader } from './browser-data-loader';
@NgModule({
providers: [
{ provide: DataLoader, useClass: BrowserDataLoader }
]
})
export class BrowserDataLoaderModule {
}

View File

@@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { DataLoader } from './data-loader';
@Injectable()
export class BrowserDataLoader extends DataLoader {
protected prefix: string;
protected suffix: string;
constructor(private http: Http) {
super();
this.prefix = 'assets/data';
this.suffix = '.json';
}
public getData(name: string): Observable<any> {
return this.http.get(`${this.prefix}/${this.language}/${name}${this.suffix}`, {}).map((response: Response) => {
return response.json();
});
}
}

View File

@@ -0,0 +1,21 @@
import { Observable } from 'rxjs/Observable';
export abstract class DataLoader {
protected language: string;
protected abstract prefix: string;
protected abstract suffix: string;
constructor() {
this.language = 'en';
}
public setLanguage(language: string): void {
this.language = language;
}
abstract getData(name: string): Observable<any>;
}

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { DataLoader } from './data-loader';
import { ServerDataLoader } from './server-data-loader';
@NgModule({
providers: [
{ provide: DataLoader, useClass: ServerDataLoader }
]
})
export class ServerDataLoaderModule {
}

View File

@@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import * as fs from 'fs';
import { DataLoader } from './data-loader';
@Injectable()
export class ServerDataLoader extends DataLoader {
protected prefix: string;
protected suffix: string;
constructor() {
super();
this.prefix = 'dist/assets/data';
this.suffix = '.json';
}
public getData(name: string): Observable<any> {
return Observable.create((observer: any) => {
observer.next(JSON.parse(fs.readFileSync(`${this.prefix}/${this.language}/${name}${this.suffix}`, 'utf8')));
observer.complete();
});
}
}

View File

@@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { TransferHttp } from './transfer-http';
@NgModule({
providers: [
TransferHttp
]
})
export class TransferHttpModule {
}

View File

@@ -0,0 +1,132 @@
import { Injectable } from '@angular/core';
import { ConnectionBackend, Http, Request, RequestOptions, RequestOptionsArgs, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { TransferState } from '../transfer-state/transfer-state';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/observable/of';
@Injectable()
export class TransferHttp {
constructor(private http: Http, protected transferState: TransferState) { }
request(uri: string | Request, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getData(uri, options, (url: string, options: RequestOptionsArgs) => {
return this.http.request(url, options);
});
}
get(url: string, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getData(url, options, (url: string, options: RequestOptionsArgs) => {
return this.http.get(url, options);
});
}
post(url: string, body: any, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => {
return this.http.post(url, body, options);
});
}
put(url: string, body: any, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getData(url, options, (url: string, options: RequestOptionsArgs) => {
return this.http.put(url, options);
});
}
delete(url: string, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getData(url, options, (url: string, options: RequestOptionsArgs) => {
return this.http.delete(url, options);
});
}
patch(url: string, body: any, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => {
return this.http.patch(url, body, options);
});
}
head(url: string, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getData(url, options, (url: string, options: RequestOptionsArgs) => {
return this.http.head(url, options);
});
}
options(url: string, options?: RequestOptionsArgs): Observable<any> {
// tslint:disable-next-line:no-shadowed-variable
return this.getData(url, options, (url: string, options: RequestOptionsArgs) => {
return this.http.options(url, options);
});
}
// tslint:disable-next-line:max-line-length
private getData(uri: string | Request, options: RequestOptionsArgs, callback: (uri: string | Request, options?: RequestOptionsArgs) => Observable<Response>) {
let url = uri;
if (typeof uri !== 'string') {
url = uri.url;
}
const key = url + JSON.stringify(options);
try {
return this.resolveData(key);
} catch (e) {
return callback(uri, options)
.map((res: Response) => res.json())
.do((data: any) => {
this.setCache(key, data);
});
}
}
private getPostData(uri: string | Request, body: any, options: RequestOptionsArgs, callback: (uri: string | Request, body: any, options?: RequestOptionsArgs) => Observable<Response>) {
let url = uri;
if (typeof uri !== 'string') {
url = uri.url;
}
const key = url + JSON.stringify(body) + JSON.stringify(options);
try {
return this.resolveData(key);
} catch (e) {
return callback(uri, body, options)
.map((res: Response) => res.json())
.do((data: any) => {
this.setCache(key, data);
});
}
}
private resolveData(key: string) {
const data = this.getFromCache(key);
if (!data) {
throw new Error();
}
return Observable.of(data);
}
private setCache(key, data) {
return this.transferState.set(key, data);
}
private getFromCache(key): any {
return this.transferState.get(key);
}
}

View File

@@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { BrowserTransferState } from './browser-transfer-state';
import { TransferState } from './transfer-state';
@NgModule({
providers: [
{ provide: TransferState, useClass: BrowserTransferState }
]
})
export class BrowserTransferStateModule {
}

View File

@@ -0,0 +1,46 @@
import { Inject, Injectable } from '@angular/core';
import { Action, Store } from '@ngrx/store';
import { TransferState } from './transfer-state';
import { StoreAction, StoreActionTypes } from '../../app/store.actions';
import { AppState } from '../../app/app.reducer';
import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
@Injectable()
export class BrowserTransferState extends TransferState {
constructor(private store: Store<AppState>, @Inject(GLOBAL_CONFIG) private config: GlobalConfig) {
super();
}
initialize() {
// tslint:disable-next-line:no-string-literal
const cache: any = window['TRANSFER_STATE'] || {};
Object.keys(cache).forEach((key: string) => {
if (key !== 'actions') {
this.set(key, cache[key]);
}
});
if (this.config.prerenderStrategy === 'replay') {
if (cache.actions !== undefined) {
if (this.config.debug) {
console.info('Replay:', cache.actions);
}
this.store.dispatch(new StoreAction(StoreActionTypes.REPLAY, cache.actions));
} else {
console.info('No actions occured during prerender.');
}
} else if (this.config.prerenderStrategy === 'rehydrate') {
if (this.config.debug) {
console.info('Rehydrate:', cache.state);
}
this.store.dispatch(new StoreAction(StoreActionTypes.REHYDRATE, cache.state));
} else {
console.warn([this.config.prerenderStrategy, 'is not a valid prerender strategy!'].join(' '));
}
}
}

View File

@@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { ServerTransferState } from './server-transfer-state';
import { TransferState } from './transfer-state';
@NgModule({
providers: [
{ provide: TransferState, useClass: ServerTransferState }
]
})
export class ServerTransferStateModule {
}

View File

@@ -0,0 +1,37 @@
import { Inject, Injectable, RendererFactory2, ViewEncapsulation } from '@angular/core';
import { INITIAL_CONFIG, PlatformState } from '@angular/platform-server';
import { TransferState } from './transfer-state';
@Injectable()
export class ServerTransferState extends TransferState {
constructor(private state: PlatformState, private rendererFactory: RendererFactory2) {
super();
}
inject() {
try {
const document: any = this.state.getDocument();
const transferStateString = JSON.stringify(this.toJson());
const renderer = this.rendererFactory.createRenderer(document, {
id: '-1',
encapsulation: ViewEncapsulation.None,
styles: [],
data: {}
});
const head = document.children[1].children[0];
if (head.name !== 'head') {
throw new Error('Please have <head> as the first element in your document');
}
const script = renderer.createElement('script');
renderer.setValue(script, `window['TRANSFER_STATE'] = ${transferStateString}`);
renderer.appendChild(head, script);
} catch (e) {
console.error(e);
}
}
}

View File

@@ -0,0 +1,40 @@
import { Injectable } from '@angular/core';
import { Action } from '@ngrx/store';
import { Store } from '@ngrx/store';
@Injectable()
export class TransferState {
protected map = new Map<string, any>();
keys() {
return this.map.keys();
}
get(key: string): any {
return this.map.get(key);
}
set(key: string, value: any): Map<string, any> {
return this.map.set(key, value);
}
toJson(): any {
const json: any = {};
Array.from(this.keys())
.forEach((key: string) => {
json[key] = this.get(key);
});
return json;
}
initialize(): void {
console.log('Initialize does nothing!');
}
inject(): void {
console.log('Inject does nothing!');
}
}

View File

@@ -0,0 +1,28 @@
import { Inject, Injectable } from '@angular/core';
import { Action } from '@ngrx/store';
import { Effect, Actions } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { types } from '../../app/shared/ngrx/type';
import { TransferStoreEffects } from './transfer-store.effects';
import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
@Injectable()
export class BrowserTransferStoreEffects extends TransferStoreEffects {
@Effect({ dispatch: false }) log = this.actions.ofType(...types()).switchMap((action: Action) => {
if (this.config.debug) {
console.info(action);
}
return Observable.of({});
});
constructor(private actions: Actions, @Inject(GLOBAL_CONFIG) public config: GlobalConfig) {
super();
}
}

View File

@@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { BrowserTransferStoreEffects } from './browser-transfer-store.effects';
import { TransferStoreEffects } from './transfer-store.effects';
@NgModule({
providers: [
{ provide: TransferStoreEffects, useClass: BrowserTransferStoreEffects }
]
})
export class BrowserTransferStoreModule {
}

View File

@@ -0,0 +1,36 @@
import { Inject, Injectable } from '@angular/core';
import { Action } from '@ngrx/store';
import { Effect, Actions } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { types } from '../../app/shared/ngrx/type';
import { TransferStoreEffects } from './transfer-store.effects';
import { TransferState } from '../transfer-state/transfer-state';
import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
@Injectable()
export class ServerTransferStoreEffects extends TransferStoreEffects {
@Effect({ dispatch: false }) track = this.actions.ofType(...types()).switchMap((action: Action) => {
this.cacheAction(action);
return Observable.of({});
});
constructor(private actions: Actions, private cache: TransferState, @Inject(GLOBAL_CONFIG) public config: GlobalConfig) {
super();
this.cache.set('actions', new Array<Action>());
}
private cacheAction(action: Action): void {
if (this.config.debug) {
console.info('Cache:', action);
}
this.cache.get('actions').push(action);
}
}

View File

@@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { ServerTransferStoreEffects } from './server-transfer-store.effects';
import { TransferStoreEffects } from './transfer-store.effects';
@NgModule({
providers: [
{ provide: TransferStoreEffects, useClass: ServerTransferStoreEffects }
]
})
export class ServerTransferStoreModule {
}

View File

@@ -0,0 +1,3 @@
export abstract class TransferStoreEffects {
}

View File

@@ -0,0 +1,16 @@
import { TranslateLoader } from '@ngx-translate/core';
import { Observable } from 'rxjs/Observable';
import * as fs from 'fs';
export class TranslateUniversalLoader implements TranslateLoader {
constructor(private prefix: string = 'i18n', private suffix: string = '.json') { }
public getTranslation(lang: string): Observable<any> {
return Observable.create((observer: any) => {
observer.next(JSON.parse(fs.readFileSync(`${this.prefix}/${lang}${this.suffix}`, 'utf8')));
observer.complete();
});
}
}