feat(aio): add initial doc viewer
with lots of fixes from Igor and Ward <3
This commit is contained in:
@ -16,7 +16,7 @@
|
|||||||
"polyfills": "polyfills.ts",
|
"polyfills": "polyfills.ts",
|
||||||
"test": "test.ts",
|
"test": "test.ts",
|
||||||
"tsconfig": "tsconfig.json",
|
"tsconfig": "tsconfig.json",
|
||||||
"prefix": "app",
|
"prefix": "aio",
|
||||||
"styles": [
|
"styles": [
|
||||||
"styles.scss"
|
"styles.scss"
|
||||||
],
|
],
|
||||||
|
@ -7,8 +7,10 @@ describe('site App', function() {
|
|||||||
page = new SitePage();
|
page = new SitePage();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display message saying app works', () => {
|
it('should show features text after clicking "Features"', () => {
|
||||||
page.navigateTo();
|
page.navigateTo();
|
||||||
expect(page.getParagraphText()).toEqual('home-page works!');
|
page.featureLink.click().then(() => {
|
||||||
|
expect(page.getDocViewerText()).toContain('Progressive web apps');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
export class SitePage {
|
export class SitePage {
|
||||||
|
|
||||||
|
featureLink = element(by.css('md-toolbar a[aioNavLink=features]'));
|
||||||
|
|
||||||
navigateTo() {
|
navigateTo() {
|
||||||
return browser.get('/');
|
return browser.get('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
getParagraphText() {
|
getDocViewerText() {
|
||||||
return element(by.css('app-home-page p')).getText();
|
return element(by.css('aio-doc-viewer')).getText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<md-toolbar color="primary" class="app-toolbar">
|
<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>
|
</md-toolbar>
|
||||||
<section class="app-content">
|
<section class="app-content">
|
||||||
<router-outlet></router-outlet>
|
<aio-doc-viewer [doc]="navEngine.currentDoc"></aio-doc-viewer>
|
||||||
</section>
|
</section>
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
.fill-remaining-space {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
.nav-link {
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { NavEngine } from './nav-engine/nav-engine';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-shell',
|
selector: 'aio-shell',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss']
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = 'app works!';
|
title = 'app works!';
|
||||||
|
constructor(public navEngine: NavEngine) {}
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,23 @@ import { NgModule } from '@angular/core';
|
|||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { MdToolbarModule } from '@angular/material/toolbar';
|
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({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent
|
AppComponent,
|
||||||
|
DocViewerComponent,
|
||||||
|
NavLinkDirective
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
MdToolbarModule.forRoot(),
|
MdToolbarModule.forRoot(),
|
||||||
RouterModule.forRoot([
|
MdButtonModule.forRoot()
|
||||||
{ path: '', loadChildren: './home-page/home-page.module#HomePageModule'}
|
|
||||||
])
|
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [NavEngine],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
28
angular.io/src/app/doc-viewer/doc-viewer.component.spec.ts
Normal file
28
angular.io/src/app/doc-viewer/doc-viewer.component.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
24
angular.io/src/app/doc-viewer/doc-viewer.component.ts
Normal file
24
angular.io/src/app/doc-viewer/doc-viewer.component.ts
Normal 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-ngio-docs',
|
selector: 'aio-ngio-docs',
|
||||||
templateUrl: './docs-app.component.html',
|
templateUrl: './docs-app.component.html',
|
||||||
styleUrls: ['./docs-app.component.css']
|
styleUrls: ['./docs-app.component.css']
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home-page',
|
selector: 'aio-home-page',
|
||||||
templateUrl: './home-page.component.html',
|
templateUrl: './home-page.component.html',
|
||||||
styleUrls: ['./home-page.component.css']
|
styleUrls: ['./home-page.component.css']
|
||||||
})
|
})
|
||||||
|
32
angular.io/src/app/nav-engine/nav-engine.ts
Normal file
32
angular.io/src/app/nav-engine/nav-engine.ts
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
19
angular.io/src/app/nav-engine/nav-link.ts
Normal file
19
angular.io/src/app/nav-engine/nav-link.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
16
angular.io/src/app/page-manager.service.spec.ts
Normal file
16
angular.io/src/app/page-manager.service.spec.ts
Normal 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();
|
||||||
|
}));
|
||||||
|
});
|
8
angular.io/src/app/page-manager.service.ts
Normal file
8
angular.io/src/app/page-manager.service.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PageManagerService {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
}
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<app-shell></app-shell>
|
<aio-shell></aio-shell>
|
||||||
|
|
||||||
<!-- TODO: google analytics -->
|
<!-- TODO: google analytics -->
|
||||||
<!-- TODO: google feedback -->
|
<!-- TODO: google feedback -->
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// import 'core-js/es6/regexp';
|
// import 'core-js/es6/regexp';
|
||||||
// import 'core-js/es6/map';
|
// import 'core-js/es6/map';
|
||||||
// import 'core-js/es6/set';
|
// import 'core-js/es6/set';
|
||||||
|
import 'reflect-metadata';
|
||||||
|
|
||||||
|
|
||||||
// If you need to support the browsers/features below, uncomment the import
|
// If you need to support the browsers/features below, uncomment the import
|
||||||
|
@ -98,8 +98,8 @@
|
|||||||
"check-type"
|
"check-type"
|
||||||
],
|
],
|
||||||
|
|
||||||
"directive-selector": [true, "attribute", "app", "camelCase"],
|
"directive-selector": [true, "attribute", "aio", "camelCase"],
|
||||||
"component-selector": [true, "element", "app", "kebab-case"],
|
"component-selector": [true, "element", "aio", "kebab-case"],
|
||||||
"use-input-property-decorator": true,
|
"use-input-property-decorator": true,
|
||||||
"use-output-property-decorator": true,
|
"use-output-property-decorator": true,
|
||||||
"use-host-property-decorator": true,
|
"use-host-property-decorator": true,
|
||||||
|
Reference in New Issue
Block a user