feat(aio): add initial doc viewer

with lots of fixes from Igor and Ward <3
This commit is contained in:
Rob Wormald 2017-02-02 12:10:47 -08:00 committed by Igor Minar
parent 559cf9d192
commit 6e2c9cb586
20 changed files with 169 additions and 20 deletions

View File

@ -16,7 +16,7 @@
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "app",
"prefix": "aio",
"styles": [
"styles.scss"
],

View File

@ -7,8 +7,10 @@ describe('site App', function() {
page = new SitePage();
});
it('should display message saying app works', () => {
it('should show features text after clicking "Features"', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('home-page works!');
page.featureLink.click().then(() => {
expect(page.getDocViewerText()).toContain('Progressive web apps');
});
});
});

View File

@ -1,11 +1,14 @@
import { browser, element, by } from 'protractor';
export class SitePage {
featureLink = element(by.css('md-toolbar a[aioNavLink=features]'));
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-home-page p')).getText();
getDocViewerText() {
return element(by.css('aio-doc-viewer')).getText();
}
}

View File

@ -1,7 +1,10 @@
<md-toolbar color="primary" class="app-toolbar">
<span>Angular</span>
<span>Angular</span>
<span><a class="nav-link" aioNavLink="home"> Home </a></span>
<span><a class="nav-link" aioNavLink="news"> News</a></span>
<span><a class="nav-link" aioNavLink="features"> Features</a></span>
<span class="fill-remaining-space"></span>
</md-toolbar>
<section class="app-content">
<router-outlet></router-outlet>
<aio-doc-viewer [doc]="navEngine.currentDoc"></aio-doc-viewer>
</section>

View File

@ -0,0 +1,8 @@
.fill-remaining-space {
flex: 1 1 auto;
}
.nav-link {
margin-right: 10px;
margin-left: 20px;
cursor: pointer;
}

View File

@ -1,10 +1,11 @@
import { Component } from '@angular/core';
import { NavEngine } from './nav-engine/nav-engine';
@Component({
selector: 'app-shell',
selector: 'aio-shell',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'app works!';
constructor(public navEngine: NavEngine) {}
}

View File

@ -3,19 +3,23 @@ import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { MdToolbarModule } from '@angular/material/toolbar';
import { MdButtonModule} from '@angular/material/button';
import { DocViewerComponent } from './doc-viewer/doc-viewer.component';
import { NavEngine } from './nav-engine/nav-engine';
import { NavLinkDirective } from './nav-engine/nav-link';
@NgModule({
declarations: [
AppComponent
AppComponent,
DocViewerComponent,
NavLinkDirective
],
imports: [
BrowserModule,
MdToolbarModule.forRoot(),
RouterModule.forRoot([
{ path: '', loadChildren: './home-page/home-page.module#HomePageModule'}
])
MdButtonModule.forRoot()
],
providers: [],
providers: [NavEngine],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,28 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { DocViewerComponent } from './doc-viewer.component';
describe('DocViewerComponent', () => {
let component: DocViewerComponent;
let fixture: ComponentFixture<DocViewerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DocViewerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DocViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,24 @@
import { Component, OnInit, Input, ElementRef, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'aio-doc-viewer',
templateUrl: './doc-viewer.component.html',
styleUrls: ['./doc-viewer.component.css'],
// TODO(robwormald): shadow DOM and emulated don't work here (?!)
// encapsulation: ViewEncapsulation.Native
})
export class DocViewerComponent implements OnInit {
@Input()
set doc(currentDoc) {
if (currentDoc) {
this.element.nativeElement.innerHTML = currentDoc.content;
}
}
constructor(private element: ElementRef) { }
ngOnInit() {
}
}

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-ngio-docs',
selector: 'aio-ngio-docs',
templateUrl: './docs-app.component.html',
styleUrls: ['./docs-app.component.css']
})

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-home-page',
selector: 'aio-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})

View File

@ -0,0 +1,32 @@
declare var fetch;
// TODO(robwormald): figure out how to handle this properly...
const siteMap = [
{ 'title': 'Home', 'url': 'assets/documents/home.html', id: 'home'},
{ 'title': 'Features', 'url': 'assets/documents/features.html', id: 'features'},
{ 'title': 'News', 'url': 'assets/documents/news.html', id: 'news'}
];
export class NavEngine {
currentDoc: any;
constructor() {}
navigate(documentId) {
console.log('navigating to', documentId);
const doc = siteMap.find(d => d.id === documentId);
if (doc) {
this._fetchDoc(doc.url)
.then(content => {
console.log('fetched content', content);
this.currentDoc = Object.assign({}, doc, {content});
});
}
}
private _fetchDoc(url) {
// TODO(robwormald): use Http proper once new API is done.
return fetch(url).then(res => res.text());
}
}

View File

@ -0,0 +1,19 @@
import { Directive, HostListener, Input } from '@angular/core';
import { NavEngine } from './nav-engine';
@Directive({
selector: '[aioNavLink]'
})
export class NavLinkDirective {
@Input()
aioNavLink: string;
constructor(private navEngine: NavEngine) { }
@HostListener('click', ['$event'])
onClick($event) {
this.navEngine.navigate(this.aioNavLink);
return false;
}
}

View File

@ -0,0 +1,16 @@
/* tslint:disable:no-unused-variable */
import { TestBed, async, inject } from '@angular/core/testing';
import { PageManagerService } from './page-manager.service';
describe('PageManagerService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [PageManagerService]
});
});
it('should ...', inject([PageManagerService], (service: PageManagerService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,8 @@
import { Injectable } from '@angular/core';
@Injectable()
export class PageManagerService {
constructor() { }
}

View File

@ -23,7 +23,7 @@
<body>
<app-shell></app-shell>
<aio-shell></aio-shell>
<!-- TODO: google analytics -->
<!-- TODO: google feedback -->

View File

@ -15,6 +15,7 @@
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/set';
import 'reflect-metadata';
// If you need to support the browsers/features below, uncomment the import

View File

@ -98,8 +98,8 @@
"check-type"
],
"directive-selector": [true, "attribute", "app", "camelCase"],
"component-selector": [true, "element", "app", "kebab-case"],
"directive-selector": [true, "attribute", "aio", "camelCase"],
"component-selector": [true, "element", "aio", "kebab-case"],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,