diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 88d1123e..25d34648 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -4,6 +4,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AppComponent } from './app.component'; import { ToolbarModule } from './toolbar/toolbar.module'; import { MatSidenavModule, MatListModule } from '@angular/material'; +import { SeoService } from './services/seo.service'; describe('AppComponent', () => { let component: AppComponent; @@ -19,7 +20,8 @@ describe('AppComponent', () => { MatSidenavModule, MatListModule ], - declarations: [AppComponent] + declarations: [AppComponent], + providers: [SeoService] }).compileComponents(); }) ); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 002b98cb..86515ea4 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,12 @@ -import { Component } from "@angular/core"; +import { Component, OnInit } from '@angular/core'; +import { + Router, + ActivatedRoute, + NavigationEnd, + RouterEvent +} from '@angular/router'; +import { filter, map, mergeMap } from 'rxjs/operators'; +import { SeoService, SeoData } from './services/seo.service'; interface Menu { title: string; @@ -7,31 +15,55 @@ interface Menu { } @Component({ - selector: "app-root", - templateUrl: "./app.component.html", - styleUrls: ["./app.component.scss"] + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] }) -export class AppComponent { +export class AppComponent implements OnInit { menus: Menu[] = [ { - title: "Home", - link: "/", + title: 'Home', + link: '/', options: { exact: true } }, { - title: "Operators", - link: "/operators", + title: 'Operators', + link: '/operators', options: { exact: false } }, { - title: "Companies", - link: "/companies", + title: 'Companies', + link: '/companies', options: { exact: false } }, { - title: "Team", - link: "/team", + title: 'Team', + link: '/team', options: { exact: false } } ]; + + constructor( + private _router: Router, + private _activatedRoute: ActivatedRoute, + private _seo: SeoService + ) {} + + ngOnInit() { + this._router.events + .pipe( + filter((e: RouterEvent) => e instanceof NavigationEnd), + map(() => { + let route = this._activatedRoute; + while (route.firstChild) { + route = route.firstChild; + } + return route; + }), + filter(route => route.outlet === 'primary'), + mergeMap(route => route.data), + filter((data: SeoData) => data.title !== undefined) + ) + .subscribe((data: SeoData) => this._seo.setHeaders(data)); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a1c48130..b167c370 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,3 +1,4 @@ +import { SeoService } from './services/seo.service'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule } from '@angular/core'; @@ -17,7 +18,7 @@ import { AppRoutingModule } from './app-routing.module'; MatSidenavModule, AppRoutingModule ], - providers: [], + providers: [SeoService], bootstrap: [AppComponent] }) export class AppModule {} diff --git a/src/app/companies/companies-routing.module.ts b/src/app/companies/companies-routing.module.ts index 9531d7b2..c8f9cb72 100644 --- a/src/app/companies/companies-routing.module.ts +++ b/src/app/companies/companies-routing.module.ts @@ -3,7 +3,13 @@ import { Routes, RouterModule } from '@angular/router'; import { CompaniesComponent } from './companies.component'; -const routes: Routes = [{ path: '', component: CompaniesComponent }]; +const routes: Routes = [ + { + path: '', + component: CompaniesComponent, + data: { title: ['Companies'], description: 'Companies that use RxJS...' } + } +]; @NgModule({ imports: [RouterModule.forChild(routes)], diff --git a/src/app/companies/companies.component.ts b/src/app/companies/companies.component.ts index 0dbc9a29..cb729f61 100644 --- a/src/app/companies/companies.component.ts +++ b/src/app/companies/companies.component.ts @@ -1,12 +1,10 @@ -import { Component, OnInit } from "@angular/core"; +import { Component } from '@angular/core'; @Component({ - selector: "app-companies", - templateUrl: "./companies.component.html", - styleUrls: ["./companies.component.scss"] + selector: 'app-companies', + templateUrl: './companies.component.html', + styleUrls: ['./companies.component.scss'] }) -export class CompaniesComponent implements OnInit { +export class CompaniesComponent { constructor() {} - - ngOnInit() {} } diff --git a/src/app/operators/components/operator/operator.component.ts b/src/app/operators/components/operator/operator.component.ts index 453a59d8..b5c4b579 100644 --- a/src/app/operators/components/operator/operator.component.ts +++ b/src/app/operators/components/operator/operator.component.ts @@ -2,28 +2,64 @@ import { Component, Input, OnInit, - ChangeDetectionStrategy -} from "@angular/core"; -import { OperatorDoc } from "../../../../operator-docs/operator.model"; + ChangeDetectionStrategy, + Inject, + InjectionToken +} from '@angular/core'; +import { Router, ActivatedRoute } from '@angular/router'; +import { SeoService } from '../../../services/seo.service'; +import { OperatorDoc } from '../../../../operator-docs/operator.model'; +import { pluck } from 'rxjs/operators'; + +export const OPERATOR_TOKEN = new InjectionToken('operators'); @Component({ - selector: "app-operator", - templateUrl: "./operator.component.html", - styleUrls: ["./operator.component.scss"], - changeDetection: ChangeDetectionStrategy.OnPush + selector: 'app-operator', + templateUrl: './operator.component.html', + styleUrls: ['./operator.component.scss'] }) -export class OperatorComponent { - @Input() operator: OperatorDoc; - - private readonly baseSourceUrl = "https://github.com/ReactiveX/rxjs/blob/master/src/operators/"; - private readonly baseSpecUrl = "http://reactivex.io/rxjs/test-file/spec-js/operators"; +export class OperatorComponent implements OnInit { + public operator: OperatorDoc; + public operatorsMap = new Map(); + + private readonly baseSourceUrl = 'https://github.com/ReactiveX/rxjs/blob/master/src/operators/'; + private readonly baseSpecUrl = 'http://reactivex.io/rxjs/test-file/spec-js/operators'; + + constructor( + private _router: Router, + private _activatedRoute: ActivatedRoute, + @Inject(OPERATOR_TOKEN) public operators: OperatorDoc[], + private _seo: SeoService + ) {} + + ngOnInit() { + this.operators.forEach((op: OperatorDoc) => { + this.operatorsMap.set(op.name, op); + }); + this._activatedRoute.params + .pipe(pluck('operator')) + .subscribe((name: string) => { + if (this.operatorsMap.has(name)) { + this.operator = this.operatorsMap.get(name); + } else { + this.notfound(); + return; + } + this._seo.setHeaders({ + title: [this.operator.name, this.operator.operatorType], + description: this.operator.shortDescription + ? this.operator.shortDescription.description + : '' + }); + }); + } get operatorName() { return this.operator.name; } get signature() { - return this.operator.signature || "Signature Placeholder"; + return this.operator.signature || 'Signature Placeholder'; } get marbleUrl() { @@ -78,4 +114,9 @@ export class OperatorComponent { get additionalResources() { return this.operator.additionalResources || []; } + + private notfound() { + this._router.navigate(['/operators']); + return {}; + } } diff --git a/src/app/operators/components/related-operators/related-operators.component.html b/src/app/operators/components/related-operators/related-operators.component.html index 2da9fa6f..a0b853e5 100644 --- a/src/app/operators/components/related-operators/related-operators.component.html +++ b/src/app/operators/components/related-operators/related-operators.component.html @@ -1,6 +1,6 @@ diff --git a/src/app/operators/operators-routing.module.ts b/src/app/operators/operators-routing.module.ts index 83354d0e..34cbaa05 100644 --- a/src/app/operators/operators-routing.module.ts +++ b/src/app/operators/operators-routing.module.ts @@ -2,8 +2,16 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { OperatorsComponent } from './operators.component'; +import { OperatorComponent } from './components/operator/operator.component'; -const routes: Routes = [{ path: '', component: OperatorsComponent }]; +const routes: Routes = [ + { + path: '', + component: OperatorsComponent, + data: { title: ['Operators'], description: 'All the RxJS operators...' }, + children: [{ path: ':operator', component: OperatorComponent }] + } +]; @NgModule({ imports: [RouterModule.forChild(routes)], diff --git a/src/app/operators/operators.component.html b/src/app/operators/operators.component.html index ef256efa..91046a0e 100644 --- a/src/app/operators/operators.component.html +++ b/src/app/operators/operators.component.html @@ -11,15 +11,13 @@

{{ category }}

+ [routerLink]="['/operators', operator.name]" + routerLinkActive="active"> {{ operator.name }} - - +