From 93c0ab7131fa3409511729ca350b89b59237dcd6 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 1 Mar 2017 14:34:27 +0000 Subject: [PATCH] fix(aio): remove previous files --- .../doc-viewer/doc-viewer.component.spec.ts | 306 ------------- .../app/doc-viewer/doc-viewer.component.ts | 139 ------ .../nav-engine/doc-fetching.service.spec.ts | 2 - .../app/nav-engine/doc-fetching.service.ts | 80 ---- .../app/nav-engine/doc-metadata.service.ts | 7 - aio/src/app/nav-engine/doc.model.ts | 54 --- aio/src/app/nav-engine/doc.service.spec.ts | 83 ---- aio/src/app/nav-engine/doc.service.ts | 57 --- aio/src/app/nav-engine/index.ts | 21 - .../app/nav-engine/nav-engine.service.spec.ts | 39 -- aio/src/app/nav-engine/nav-engine.service.ts | 34 -- aio/src/app/nav-engine/nav-link.directive.ts | 19 - .../app/nav-engine/nav-map.service.spec.ts | 199 --------- aio/src/app/nav-engine/nav-map.service.ts | 88 ---- aio/src/app/sidenav/menu.component.scss | 23 - aio/src/app/sidenav/menu.component.ts | 16 - aio/src/app/sidenav/nav-item.component.html | 19 - aio/src/app/sidenav/nav-item.component.scss | 114 ----- aio/src/app/sidenav/nav-item.component.ts | 83 ---- aio/src/app/sidenav/sidenav.component.html | 13 - aio/src/app/sidenav/sidenav.component.scss | 27 -- aio/src/app/sidenav/sidenav.component.spec.ts | 223 ---------- aio/src/app/sidenav/sidenav.component.ts | 68 --- aio/src/content/navmap.json | 402 ------------------ 24 files changed, 2116 deletions(-) delete mode 100644 aio/src/app/doc-viewer/doc-viewer.component.spec.ts delete mode 100644 aio/src/app/doc-viewer/doc-viewer.component.ts delete mode 100644 aio/src/app/nav-engine/doc-fetching.service.spec.ts delete mode 100644 aio/src/app/nav-engine/doc-fetching.service.ts delete mode 100644 aio/src/app/nav-engine/doc-metadata.service.ts delete mode 100644 aio/src/app/nav-engine/doc.model.ts delete mode 100644 aio/src/app/nav-engine/doc.service.spec.ts delete mode 100644 aio/src/app/nav-engine/doc.service.ts delete mode 100644 aio/src/app/nav-engine/index.ts delete mode 100644 aio/src/app/nav-engine/nav-engine.service.spec.ts delete mode 100644 aio/src/app/nav-engine/nav-engine.service.ts delete mode 100644 aio/src/app/nav-engine/nav-link.directive.ts delete mode 100644 aio/src/app/nav-engine/nav-map.service.spec.ts delete mode 100644 aio/src/app/nav-engine/nav-map.service.ts delete mode 100644 aio/src/app/sidenav/menu.component.scss delete mode 100644 aio/src/app/sidenav/menu.component.ts delete mode 100644 aio/src/app/sidenav/nav-item.component.html delete mode 100644 aio/src/app/sidenav/nav-item.component.scss delete mode 100644 aio/src/app/sidenav/nav-item.component.ts delete mode 100644 aio/src/app/sidenav/sidenav.component.html delete mode 100644 aio/src/app/sidenav/sidenav.component.scss delete mode 100644 aio/src/app/sidenav/sidenav.component.spec.ts delete mode 100644 aio/src/app/sidenav/sidenav.component.ts delete mode 100644 aio/src/content/navmap.json diff --git a/aio/src/app/doc-viewer/doc-viewer.component.spec.ts b/aio/src/app/doc-viewer/doc-viewer.component.spec.ts deleted file mode 100644 index 4b40ac6741..0000000000 --- a/aio/src/app/doc-viewer/doc-viewer.component.spec.ts +++ /dev/null @@ -1,306 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { Component, DebugElement } from '@angular/core'; - -import { ComponentFactoryResolver, ElementRef, Injector, NgModule, OnInit, ViewChild } from '@angular/core'; - -import { Doc, DocMetadata } from '../nav-engine'; -import { DocViewerComponent } from '../doc-viewer/doc-viewer.component'; - -import { embeddedComponents, EmbeddedComponents } from '../embedded'; - - -/// Embedded Test Components /// - -///// FooComponent ///// - -@Component({ - selector: 'aio-foo', - template: `Foo Component` -}) -class FooComponent { } - -///// BarComponent ///// - -@Component({ - selector: 'aio-bar', - template: ` -
-

Bar Component

-

-
- ` -}) -class BarComponent implements OnInit { - - @ViewChild('barContent') barContentRef: ElementRef; - - constructor(public elementRef: ElementRef) { } - - // Project content in ngOnInit just like CodeExampleComponent - ngOnInit() { - // Security: this is a test component; never deployed - this.barContentRef.nativeElement.innerHTML = this.elementRef.nativeElement.aioBarContent; - } -} - -///// BazComponent ///// - -@Component({ - selector: 'aio-baz', - template: ` -
++++++++++++++
-

Baz Component

-

-
++++++++++++++
- ` -}) -class BazComponent implements OnInit { - - @ViewChild('bazContent') bazContentRef: ElementRef; - - constructor(public elementRef: ElementRef) { } - - // Project content in ngOnInit just like CodeExampleComponent - ngOnInit() { - // Security: this is a test component; never deployed - this.bazContentRef.nativeElement.innerHTML = this.elementRef.nativeElement.aioBazContent; - } -} -///// Test Module ////// - -const embeddedTestComponents = [FooComponent, BarComponent, BazComponent, ...embeddedComponents]; - -@NgModule({ - entryComponents: embeddedTestComponents -}) -class TestModule { } - -//// Test Component ////// - -@Component({ - selector: 'aio-test', - template: ` - Test Component - ` -}) -class TestComponent { - private currentDoc: Doc; - - @ViewChild(DocViewerComponent) docViewer: DocViewerComponent; - - setDoc(doc: Doc) { - if (this.docViewer) { - this.docViewer.doc = doc; - } - } -} - -//////// Tests ////////////// - -describe('DocViewerComponent', () => { - const fakeDocMetadata: DocMetadata = { docId: 'fake', title: 'fake Doc' }; - let component: TestComponent; - let docViewerDE: DebugElement; - let docViewerEl: HTMLElement; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ TestModule ], - declarations: [ - TestComponent, - DocViewerComponent, - embeddedTestComponents - ], - providers: [ - {provide: EmbeddedComponents, useValue: {components: embeddedTestComponents}} - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(TestComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - docViewerDE = fixture.debugElement.children[0]; - docViewerEl = docViewerDE.nativeElement; - }); - - it('should create a DocViewer', () => { - expect(component.docViewer).toBeTruthy(); - }); - - it(('should display nothing when set DocViewer.doc to doc w/o content'), () => { - component.docViewer.doc = { metadata: fakeDocMetadata, content: '' }; - expect(docViewerEl.innerHTML).toBe(''); - }); - - it(('should display simple static content doc'), () => { - const content = '

Howdy, doc viewer

'; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - expect(docViewerEl.innerHTML).toEqual(content); - }); - - it(('should display nothing after reset static content doc'), () => { - const content = '

Howdy, doc viewer

'; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - fixture.detectChanges(); - component.docViewer.doc = { metadata: fakeDocMetadata, content: '' }; - expect(docViewerEl.innerHTML).toEqual(''); - }); - - it(('should apply FooComponent'), () => { - const content = ` -

Above Foo

-

-

Below Foo

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - const fooHtml = docViewerEl.querySelector('aio-foo').innerHTML; - expect(fooHtml).toContain('Foo Component'); - }); - - it(('should apply multiple FooComponents'), () => { - const content = ` -

Above Foo

-

-
- Holds a - Ignored text -
-

Below Foo

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - const foos = docViewerEl.querySelectorAll('aio-foo'); - expect(foos.length).toBe(2); - }); - - it(('should apply BarComponent'), () => { - const content = ` -

Above Bar

- -

Below Bar

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - const barHtml = docViewerEl.querySelector('aio-bar').innerHTML; - expect(barHtml).toContain('Bar Component'); - }); - - it(('should project bar content into BarComponent'), () => { - const content = ` -

Above Bar

- ###bar content### -

Below Bar

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - - // necessary to trigger projection within ngOnInit - fixture.detectChanges(); - - const barHtml = docViewerEl.querySelector('aio-bar').innerHTML; - expect(barHtml).toContain('###bar content###'); - }); - - - it(('should include Foo and Bar'), () => { - const content = ` -

Top

-

ignored

- ###bar content### -

-

Bottom

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - - // necessary to trigger Bar's projection within ngOnInit - fixture.detectChanges(); - - const foos = docViewerEl.querySelectorAll('aio-foo'); - expect(foos.length).toBe(2, 'should have 2 foos'); - - const barHtml = docViewerEl.querySelector('aio-bar').innerHTML; - expect(barHtml).toContain('###bar content###', 'should have bar with projected content'); - }); - - it(('should not include Bar within Foo'), () => { - const content = ` -

Top

-
- - ###bar content### - -
-

-

Bottom

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - - // necessary to trigger Bar's projection within ngOnInit - fixture.detectChanges(); - - const foos = docViewerEl.querySelectorAll('aio-foo'); - expect(foos.length).toBe(2, 'should have 2 foos'); - - const bars = docViewerEl.querySelectorAll('aio-bar'); - expect(bars.length).toBe(0, 'did not expect Bar inside Foo'); - }); - - // because FooComponents are processed before BazComponents - it(('should include Foo within Bar'), () => { - const content = ` -

Top

- -
- Inner -
-
-

-

Bottom

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - - // necessary to trigger Bar's projection within ngOnInit - fixture.detectChanges(); - - const foos = docViewerEl.querySelectorAll('aio-foo'); - expect(foos.length).toBe(2, 'should have 2 foos'); - - const bars = docViewerEl.querySelectorAll('aio-bar'); - expect(bars.length).toBe(1, 'should have a bar'); - expect(bars[0].innerHTML).toContain('Bar Component', 'should have bar template content'); - }); - - // The tag and its inner content is copied - // But the BazComponent is not created and therefore its template content is not displayed - // because BarComponents are processed before BazComponents - // and no chance for first Baz inside Bar to be processed by builder. - it(('should NOT include Bar within Baz'), () => { - const content = ` -

Top

- -
- Inner ---baz stuff--- -
-
-

---More baz--

-

Bottom

- `; - component.docViewer.doc = { metadata: fakeDocMetadata, content }; - - // necessary to trigger Bar's projection within ngOnInit - fixture.detectChanges(); - const bazs = docViewerEl.querySelectorAll('aio-baz'); - - // Both baz tags are there ... - expect(bazs.length).toBe(2, 'should have 2 bazs'); - - expect(bazs[0].innerHTML).not.toContain('Baz Component', - 'did not expect 1st Baz template content'); - - expect(bazs[1].innerHTML).toContain('Baz Component', - 'expected 2nd Baz template content'); - - }); -}); diff --git a/aio/src/app/doc-viewer/doc-viewer.component.ts b/aio/src/app/doc-viewer/doc-viewer.component.ts deleted file mode 100644 index 182e15549d..0000000000 --- a/aio/src/app/doc-viewer/doc-viewer.component.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { - Component, ComponentFactory, ComponentFactoryResolver, ComponentRef, - DoCheck, ElementRef, Injector, Input, OnDestroy, ViewEncapsulation -} from '@angular/core'; - -import { Doc, DocMetadata, DocMetadataService, NavNode } from '../nav-engine'; -import { EmbeddedComponents } from '../embedded'; - -interface EmbeddedComponentFactory { - contentPropertyName: string; - factory: ComponentFactory; -} - -// Initialization prevents flicker once pre-rendering is on -const initialDocViewerElement = document.querySelector('aio-doc-viewer'); -const initialDocViewerContent = initialDocViewerElement ? initialDocViewerElement.innerHTML : ''; - -@Component({ - selector: 'aio-doc-viewer', - template: '', - providers: [ DocMetadataService ], - styles: [ ` - :host >>> doc-title.not-found h1 { - color: white; - background-color: red; - } - `] - // TODO(robwormald): shadow DOM and emulated don't work here (?!) - // encapsulation: ViewEncapsulation.Native -}) -export class DocViewerComponent implements DoCheck, OnDestroy { - - private displayedDoc: DisplayedDoc; - private embeddedComponentFactories: Map = new Map(); - private hostElement: HTMLElement; - - constructor( - componentFactoryResolver: ComponentFactoryResolver, - elementRef: ElementRef, - embeddedComponents: EmbeddedComponents, - private docMetadataService: DocMetadataService, - private injector: Injector - ) { - this.hostElement = elementRef.nativeElement; - // Security: the initialDocViewerContent comes from the prerendered DOM and is considered to be secure - this.hostElement.innerHTML = initialDocViewerContent; - - for (const component of embeddedComponents.components) { - const factory = componentFactoryResolver.resolveComponentFactory(component); - const selector = factory.selector; - const contentPropertyName = this.selectorToContentPropertyName(selector); - this.embeddedComponentFactories.set(selector, { contentPropertyName, factory }); - } - } - - @Input() - set doc(newDoc: Doc) { - this.ngOnDestroy(); - if (newDoc) { - this.docMetadataService.metadata = newDoc.metadata; - window.scrollTo(0, 0); - this.build(newDoc); - } - } - - /** - * Add doc content to host element and build it out with embedded components - */ - private build(doc: Doc) { - - const displayedDoc = this.displayedDoc = new DisplayedDoc(doc); - - // security: the doc.content is always authored by the documentation team - // and is considered to be safe - this.hostElement.innerHTML = doc.content || ''; - - if (!doc.content) { return; } - - // TODO(i): why can't I use for-of? why doesn't typescript like Map#value() iterators? - this.embeddedComponentFactories.forEach(({ contentPropertyName, factory }, selector) => { - const embeddedComponentElements = this.hostElement.querySelectorAll(selector); - - // cast due to https://github.com/Microsoft/TypeScript/issues/4947 - for (const element of embeddedComponentElements as any as HTMLElement[]){ - // hack: preserve the current element content because the factory will empty it out - // security: the source of this innerHTML is always authored by the documentation team - // and is considered to be safe - element[contentPropertyName] = element.innerHTML; - displayedDoc.addEmbeddedComponent(factory.create(this.injector, [], element)); - } - }); - } - - ngDoCheck() { - if (this.displayedDoc) { this.displayedDoc.detectChanges(); } - } - - ngOnDestroy() { - // destroy components otherwise there will be memory leaks - if (this.displayedDoc) { - this.displayedDoc.destroy(); - this.displayedDoc = undefined; - } - } - - /** - * Compute the component content property name by converting the selector to camelCase and appending - * 'Content', e.g. live-example => liveExampleContent - */ - private selectorToContentPropertyName(selector: string) { - return selector.replace(/-(.)/g, (match, $1) => $1.toUpperCase()) + 'Content'; - } -} - -class DisplayedDoc { - - metadata: DocMetadata; - - private embeddedComponents: ComponentRef[] = []; - - constructor(doc: Doc) { - // ignore doc.content ... don't need to keep it around - this.metadata = doc.metadata; - } - - addEmbeddedComponent(component: ComponentRef) { - this.embeddedComponents.push(component); - } - - detectChanges() { - this.embeddedComponents.forEach(comp => comp.changeDetectorRef.detectChanges()); - } - - destroy() { - // destroy components otherwise there will be memory leaks - this.embeddedComponents.forEach(comp => comp.destroy()); - this.embeddedComponents.length = 0; - } -} diff --git a/aio/src/app/nav-engine/doc-fetching.service.spec.ts b/aio/src/app/nav-engine/doc-fetching.service.spec.ts deleted file mode 100644 index 9b69019df8..0000000000 --- a/aio/src/app/nav-engine/doc-fetching.service.spec.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { DocFetchingService } from './doc-fetching.service'; -// Write tests when/if this service is retained. diff --git a/aio/src/app/nav-engine/doc-fetching.service.ts b/aio/src/app/nav-engine/doc-fetching.service.ts deleted file mode 100644 index 887b3b1ee6..0000000000 --- a/aio/src/app/nav-engine/doc-fetching.service.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Http, Response } from '@angular/http'; -import { Injectable } from '@angular/core'; - -import { Observable } from 'rxjs/Observable'; -import { of } from 'rxjs/observable/of'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/do'; -import 'rxjs/add/operator/map'; - -import { Doc, DocMetadata } from './doc.model'; -import { Logger } from '../logger.service'; - -@Injectable() -export class DocFetchingService { - - private base = 'content/'; - - constructor( - private http: Http, - private logger: Logger) { } - - getPath(docId: string) { - return this.base + addPathExtension(docId); - } - - /** - * Fetch document from server. - * NB: pass 404 response to caller as Doc with empty string content - * Other errors and non-OK status responses are thrown errors. - * TODO: add timeout and retry for lost connection - */ - getDocFile(docId: string): Observable { - - if (!docId) { - const emsg = 'getFile: no document id'; - this.logger.error(emsg); - throw new Error(emsg); - } - - // TODO: Metadata will be updated from file - const metadata: DocMetadata = { docId, title: docId }; - const url = this.getPath(docId); - - this.logger.log(`Fetching document file at '${url}'`); - - return this.http.get(url) - .map(res => { metadata, content: res.text() }) // TODO: It will come as JSON soon - .do(content => this.logger.log(`Fetched document file at '${url}'`) ) - .catch((error: Response) => { - if (error.status === 404) { - this.logger.error(`Document file not found at '${url}'`); - return of({metadata, content: ''} as Doc); - } else { - throw error; - } - }); - } -} - -function addPathExtension(path: string) { - if (path) { - if (path.endsWith('/')) { - return path + 'index.html'; - } else if (!path.endsWith('.html')) { - return path + '.html'; - } - } - return path; -} - -// function removePathExtension(path: string) { -// if (path) { -// if (path.endsWith('/index.html')) { -// return path.substring(0, path.length - 10); -// } else if (path.endsWith('.html')) { -// return path.substring(0, path.length - 5); -// } -// } -// return path; -// } diff --git a/aio/src/app/nav-engine/doc-metadata.service.ts b/aio/src/app/nav-engine/doc-metadata.service.ts deleted file mode 100644 index cdeda1398c..0000000000 --- a/aio/src/app/nav-engine/doc-metadata.service.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Injectable } from '@angular/core'; -import { DocMetadata } from './doc.model'; - -@Injectable() -export class DocMetadataService { - metadata: DocMetadata; -} diff --git a/aio/src/app/nav-engine/doc.model.ts b/aio/src/app/nav-engine/doc.model.ts deleted file mode 100644 index 48d9b11287..0000000000 --- a/aio/src/app/nav-engine/doc.model.ts +++ /dev/null @@ -1,54 +0,0 @@ -export interface DocMetadata { - docId: string; - title: string; -} - -export interface Doc { - metadata: DocMetadata; - content: string; -} - -/** - * UI navigation node that describes a document or container of documents - * Each node corresponds to a link in the UI. - */ -export interface NavNode { - /** unique integer id for this node */ - id: number; - /** Document id if this is a document node */ - docId: string; - /** Document path (calculated from docId) if this is a document node */ - docPath: string; - /** url to an external web page; docPath and url are mutually exclusive. */ - url?: string; - /** Title to display in the navigation link; typically shorter */ - navTitle: string; - /** Tooltip for links */ - tooltip: string; - /** Ids of ancestor nodes higher in the hierarchy */ - ancestorIds: number[]; - /** true if should not be displayed in UI. Can still be loaded directly */ - // hide?: boolean; NO NO. If the JSON says, hide, simply omit it from this map - /** If defined, this node is a container of child nodes */ - children?: NavNode[]; -} - - -/** - * Navigation for the site. - * - nodes: the top-level navigation nodes; node can have children. - * - docs: find node for a given document id. - */ -export interface NavMap { - /** - * Map that drives the UI navigation. - * Each node correspond to a navigation link in the UI. - * Supports unlimited node nesting. - */ - nodes: NavNode[]; - - /** - * NavNode for a document id in the NavMap. - */ - docs: Map; -} diff --git a/aio/src/app/nav-engine/doc.service.spec.ts b/aio/src/app/nav-engine/doc.service.spec.ts deleted file mode 100644 index cd5d8df0b5..0000000000 --- a/aio/src/app/nav-engine/doc.service.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { fakeAsync, tick } from '@angular/core/testing'; - -import { DocService } from './doc.service'; -import { Doc, DocMetadata, NavNode } from './doc.model'; -import { DocFetchingService } from './doc-fetching.service'; - -import { Observable } from 'rxjs/Observable'; -import { of } from 'rxjs/observable/of'; -import 'rxjs/add/observable/throw'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/delay'; -import 'rxjs/add/operator/first'; - -describe('DocService', () => { - let docFetchingService: DocFetchingService; - let getFileSpy: jasmine.Spy; - let loggerSpy: any; - let docService: DocService; - let testDoc: Doc; - let testDocId: string; - let testContent: string; - - beforeEach(() => { - testDocId = 'fake'; - testContent = 'fake file contents'; - testDoc = { - metadata: {docId: testDocId, title: 'Fake Title'} as DocMetadata, - content: testContent - }; - - loggerSpy = jasmine.createSpyObj('logger', ['log', 'warn', 'error']); - docFetchingService = new DocFetchingService(null, loggerSpy); - getFileSpy = spyOn(docFetchingService, 'getDocFile').and - .returnValue(of(testDoc).delay(0).first()); // first() -> completes - - docService = new DocService(docFetchingService, loggerSpy); - }); - - it('should return fake doc for fake id', fakeAsync(() => { - docService.getDoc(testDocId).subscribe(doc => - expect(doc.content).toBe(testContent) - ); - tick(); - })); - - it('should retrieve file once for first file request', fakeAsync(() => { - let doc: Doc; - expect(getFileSpy.calls.count()).toBe(0, 'no call before tick'); - docService.getDoc(testDocId).subscribe(d => doc = d); - tick(); - expect(getFileSpy.calls.count()).toBe(1, 'one call after tick'); - expect(doc).toBe(testDoc, 'expected doc'); - })); - - it('should retrieve file from cache the second time', fakeAsync(() => { - docService.getDoc(testDocId).subscribe(doc => - expect(doc).toBe(testDoc, 'expected doc from server') - ); - tick(); - expect(getFileSpy.calls.count()).toBe(1, 'one call after 1st request'); - - docService.getDoc(testDocId).subscribe(doc => - expect(doc).toBe(testDoc, 'expected doc from cache') - ); - tick(); - expect(getFileSpy.calls.count()).toBe(1, 'still only one call after 2nd request'); - })); - - it('should pass along file error through its getDoc observable result', fakeAsync(() => { - - const err = 'deliberate file error'; - getFileSpy.and.returnValue( - // simulate async error in the file retrieval - of('').delay(0).map(() => { throw new Error(err); }) - ); - - docService.getDoc(testDocId).subscribe( - doc => expect(false).toBe(true, 'should have failed'), - error => expect(error.message).toBe(err) - ); - tick(); - })); -}); diff --git a/aio/src/app/nav-engine/doc.service.ts b/aio/src/app/nav-engine/doc.service.ts deleted file mode 100644 index d5403f799a..0000000000 --- a/aio/src/app/nav-engine/doc.service.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Injectable } from '@angular/core'; - -import { Observable } from 'rxjs/Observable'; -import { of } from 'rxjs/observable/of'; -import 'rxjs/add/operator/do'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/switchMap'; - -import { Doc, NavNode } from './doc.model'; -import { DocFetchingService } from './doc-fetching.service'; -import { Logger } from '../logger.service'; - -import { NavMapService } from './nav-map.service'; - -@Injectable() -export class DocService { - private cache = new Map(); - private notFoundContent: string; - - constructor( - private fileService: DocFetchingService, - private logger: Logger - ) { } - - /** - * Get document for id, from cache if found else server. - * Pass server errors along to caller - * Constructs and caches a "Not Found" doc when fileservice returns a doc with no content. - */ - getDoc(docId: string): Observable { - const cached = this.cache.get(docId); - if (cached) { - this.logger.log(`Returned cached document for '${docId}'`); - return of(cached); - } - - return this.fileService.getDocFile(docId) - .switchMap(doc => { - this.logger.log(`Fetched document for '${docId}'`); - return doc.content ? of(doc) : - this.getNotFound() - .map(nfContent => {metadata: {docId, title: docId}, content: nfContent}); - }) - .do(doc => this.cache.set(docId, doc)); - } - - getNotFound(): Observable { - if (this.notFoundContent) { return of(this.notFoundContent); } - const nfDocId = 'not-found'; - return this.fileService.getDocFile(nfDocId) - .map(doc => { - this.logger.log(`Fetched "not found" document for '${nfDocId}'`); - this.notFoundContent = doc.content; - return doc.content; - }); - } -} diff --git a/aio/src/app/nav-engine/index.ts b/aio/src/app/nav-engine/index.ts deleted file mode 100644 index 32a4982a51..0000000000 --- a/aio/src/app/nav-engine/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { DocService } from './doc.service'; -import { DocFetchingService } from './doc-fetching.service'; -import { NavEngine } from './nav-engine.service'; -import { NavLinkDirective } from './nav-link.directive'; -import { NavMapService } from './nav-map.service'; - -export { Doc, DocMetadata, NavNode, NavMap } from './doc.model'; -export { DocMetadataService } from './doc-metadata.service'; -export { NavEngine } from './nav-engine.service'; -export { NavMapService } from './nav-map.service'; - -export const navDirectives = [ - NavLinkDirective -]; - -export const navProviders = [ - DocService, - DocFetchingService, - NavEngine, - NavMapService, -]; diff --git a/aio/src/app/nav-engine/nav-engine.service.spec.ts b/aio/src/app/nav-engine/nav-engine.service.spec.ts deleted file mode 100644 index 9e64ac767a..0000000000 --- a/aio/src/app/nav-engine/nav-engine.service.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { fakeAsync, tick} from '@angular/core/testing'; - -import { Observable } from 'rxjs/Observable'; -import { of } from 'rxjs/observable/of'; -import 'rxjs/add/operator/delay'; - -import { DocService } from './doc.service'; -import { Doc, DocMetadata, NavNode } from './doc.model'; - -import { NavEngine } from './nav-engine.service'; - -describe('NavEngine', () => { - - let fakeDoc: Doc; - let navEngine: NavEngine; - - beforeEach(() => { - fakeDoc = { - metadata: { - docId: 'fake', - title: 'All about the fake' - }, - content: 'fake content' - }; - - const docService: any = jasmine.createSpyObj('docService', ['getDoc']); - docService.getDoc.and.returnValue(of(fakeDoc).delay(0)); - - navEngine = new NavEngine(docService); - }); - - it('should set currentDoc to fake doc when navigate to fake id', fakeAsync(() => { - navEngine.navigate('fake'); - navEngine.currentDoc.subscribe(doc => - expect(doc.content).toBe(fakeDoc.content) - ); - tick(); - })); -}); diff --git a/aio/src/app/nav-engine/nav-engine.service.ts b/aio/src/app/nav-engine/nav-engine.service.ts deleted file mode 100644 index 2e2b8bdbde..0000000000 --- a/aio/src/app/nav-engine/nav-engine.service.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Injectable, OnDestroy } from '@angular/core'; - -import { ReplaySubject } from 'rxjs/ReplaySubject'; -import { Subscription } from 'rxjs/Subscription'; - -import { Doc } from './doc.model'; -import { DocService } from './doc.service'; - -@Injectable() -export class NavEngine implements OnDestroy { - - private docSubject = new ReplaySubject(1); - private subscription: Subscription; - - /** Observable of the most recent document from a `navigate` call */ - currentDoc = this.docSubject.asObservable(); - - constructor(private docService: DocService) {} - - /** - * Navigate pushes new doc for the given `id` into the `currentDoc` observable. - * TODO: handle document retrieval error - */ - navigate(docId: string) { - this.ngOnDestroy(); - this.subscription = this.docService.getDoc(docId).subscribe(doc => this.docSubject.next(doc)); - } - - ngOnDestroy() { - if (this.subscription) { this.subscription.unsubscribe(); } - } -} - - diff --git a/aio/src/app/nav-engine/nav-link.directive.ts b/aio/src/app/nav-engine/nav-link.directive.ts deleted file mode 100644 index 7d5af41361..0000000000 --- a/aio/src/app/nav-engine/nav-link.directive.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Directive, HostListener, Input } from '@angular/core'; -import { NavEngine } from './nav-engine.service'; - -@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; - } -} diff --git a/aio/src/app/nav-engine/nav-map.service.spec.ts b/aio/src/app/nav-engine/nav-map.service.spec.ts deleted file mode 100644 index 5943dbba22..0000000000 --- a/aio/src/app/nav-engine/nav-map.service.spec.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { fakeAsync, tick } from '@angular/core/testing'; -import { Http, Response } from '@angular/http'; - -import { of } from 'rxjs/observable/of'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/delay'; - -import { DocFetchingService } from './doc-fetching.service'; -import { NavNode, NavMap } from './doc.model'; -import { NavMapService } from './nav-map.service'; - -import { getTestNavMapResponse } from '../../testing/nav-map-json-response'; - -describe('NavMapService', () => { - let httpSpy: any; - let loggerSpy: any; - let navMapService: NavMapService; - let navMap: NavMap; - - beforeEach(done => { - httpSpy = jasmine.createSpyObj('http', ['get']); - httpSpy.get.and.returnValue(of(getTestNavMapResponse()).delay(0).first()); // first() -> completes - loggerSpy = jasmine.createSpyObj('logger', ['log', 'warn', 'error']); - - navMapService = new NavMapService(new DocFetchingService(null, null), httpSpy, loggerSpy); - - navMapService.navMap.first().subscribe( - nm => navMap = nm, - null, - done); - }); - - it('should return a navMap', () => { - expect(navMap).toBeDefined(); - }); - - it('should have filtered away the "cli-quickstart" because `hide`===true', () => { - const item = navMap.nodes.find(n => n.docId === 'guide/cli-quickstart'); - expect(item).toBeUndefined(); - }); - - describe('Quickstart', () => { - let item: NavNode; - - beforeEach(() => { - item = navMap.nodes.find(n => n.navTitle === 'Quickstart'); - }); - - it('should have expected item', () => { - expect(item).toBeDefined(); - }); - - it('should have expected docId', () => { - expect(item.docId).toBe('guide/quickstart'); - }); - - it('should have calculated expected docPath', () => { - expect(item.docPath).toBe('content/guide/quickstart.html'); - }); - - it('should have no ancestors because it is a top-level item', () => { - expect(item.ancestorIds).toEqual([]); - }); - }); - - describe('Getting Started', () => { - let section: NavNode; - - beforeEach(() => { - section = navMap.nodes.find(n => n.navTitle === 'Getting started'); - }); - - it('should have an id', () => { - expect(section.id).toBeGreaterThan(0); - }); - - it('should have distinct tooltip', () => { - expect(section.tooltip).not.toBe(section.navTitle); - }); - - it('should have 2 children', () => { - expect(section.children.length).toBe(2); - }); - - it('should have itself as ancestor because it has children', () => { - expect(section.ancestorIds).toEqual([section.id]); - }); - }); - - describe('Tutorial', () => { - let section: NavNode; - let intro: NavNode; - - beforeEach(() => { - section = navMap.nodes.find(n => n.navTitle === 'Tutorial'); - if (section && section.children) { - intro = section.children.find(n => n.navTitle === 'Introduction'); - } - }); - - it('should have 2 children', () => { - expect(section.children.length).toBe(2); - }); - - it('intro child\'s docId ends in "/"', () => { - expect(intro.docId[intro.docId.length - 1]).toEqual('/'); - }); - - it('intro child\'s calculated docPath ends in "index.html"', () => { - expect(intro.docPath).toMatch(/index.html$/); - }); - }); - - describe('Core (3-level)', () => { - let section: NavNode; - - beforeEach(() => { - section = navMap.nodes.find(n => n.navTitle === 'Core'); - }); - - it('should have 2 children', () => { - expect(section.children.length).toBe(2); - }); - - describe('->directives', () => { - let directives: NavNode; - - beforeEach(() => { - directives = section.children.find(n => n.navTitle === 'Directives'); - }); - - it('should have a heading docId', () => { - expect(directives.docId).toBeTruthy(); - }); - - it('should have calculated expected docPath', () => { - expect(directives.docPath).toBe('content/guide/directives.html'); - }); - - it('should have 2 children', () => { - expect(directives.children.length).toBe(2); - }); - - it('children should have two ancestor ids in lineal order', () => { - const expectedAncestors = [section.id, directives.id]; - expect(directives.children[0].ancestorIds).toEqual(expectedAncestors, '#1'); - expect(directives.children[1].ancestorIds).toEqual(expectedAncestors, '#2'); - }); - }); - }); - - describe('Empty Heading', () => { - let section: NavNode; - - beforeEach(() => { - section = navMap.nodes.find(n => n.navTitle === 'Empty Heading'); - }); - - it('should have no children', () => { - expect(section.children.length).toBe(0); - }); - - it('should have itself as ancestor because it has a `children` array', () => { - expect(section.ancestorIds).toEqual([section.id]); - }); - }); - - describe('External', () => { - let section: NavNode; - let gitter: NavNode; - - beforeEach(() => { - section = navMap.nodes.find(n => n.navTitle === 'External'); - if (section && section.children) { - gitter = section.children[0]; - } - }); - - it('should have one child (gitter)', () => { - expect(section.children.length).toBe(1); - }); - - it('child should have a url', () => { - expect(gitter.url).toBeTruthy(); - }); - - it('child should not have a docId', () => { - expect(gitter.docId).toBeUndefined(); - }); - - it('child should not have a docPath', () => { - expect(gitter.docPath).toBeUndefined(); - }); - - it('child should have parent as only ancestor id', () => { - expect(gitter.ancestorIds).toEqual([section.id]); - }); - }); -}); diff --git a/aio/src/app/nav-engine/nav-map.service.ts b/aio/src/app/nav-engine/nav-map.service.ts deleted file mode 100644 index 7fd8ee6f63..0000000000 --- a/aio/src/app/nav-engine/nav-map.service.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Http } from '@angular/http'; - -import { Observable } from 'rxjs/Observable'; -import { of } from 'rxjs/observable/of'; -import { ReplaySubject } from 'rxjs/ReplaySubject'; -import 'rxjs/add/operator/do'; -import 'rxjs/add/operator/map'; - -import { Doc, NavNode, NavMap } from './doc.model'; -import { DocFetchingService } from './doc-fetching.service'; -import { Logger } from '../logger.service'; - -const navMapUrl = 'content/navmap.json'; - -@Injectable() -export class NavMapService { - - private getDocPath: (string) => string; - private navMapSubject: ReplaySubject; - private nextNodeId = 1; - - constructor( - docFetchingService: DocFetchingService, - private http: Http, - private logger: Logger) { - this.getDocPath = docFetchingService.getPath.bind(docFetchingService); - } - - get navMap(): Observable { - return (this.navMapSubject ? this.navMapSubject : this.createNavMapSubject()).asObservable() ; - } - - private createNavMapSubject(): ReplaySubject { - this.navMapSubject = new ReplaySubject(1); - - this.http.get(navMapUrl) - .map(res => res.json().nodes) - .do(() => this.logger.log(`Fetched navigation map JSON at '${navMapUrl}'`)) - .subscribe( - navNodes => this.navMapSubject.next(this.createNavMap(navNodes)) - ); - - return this.navMapSubject; - } - - - ////// private helper functions //// - - private createNavMap(nodes: NavNode[]) { - nodes = this.removeHidden(nodes); - const navMap: NavMap = { nodes, docs: new Map()}; - nodes.forEach(node => this.adjustNode(node, navMap, [])); - return navMap; - } - - // Adjust properties of a node from JSON and build navMap.docs - private adjustNode(node: NavNode, navMap: NavMap, ancestorIds: number[] ) { - node.id = this.nextNodeId++; - node.ancestorIds = ancestorIds; - if ( node.tooltip === undefined ) { node.tooltip = node.navTitle; } - - if (node.docId) { - // This node is associated with a document - node.docId = node.docId.toLocaleLowerCase(); - node.docPath = this.getDocPath(node.docId); - navMap.docs.set(node.docId, node); - } - - - if (node.children) { - // Ancestors include self when this node has children - node.ancestorIds = ancestorIds.concat(node.id); - node.children.forEach(n => this.adjustNode(n, navMap, node.ancestorIds)); - } - } - - private removeHidden(nodes: NavNode[]) { - return nodes.filter(node => { - if (node['hide'] === true ) { return false; } - if (node.children) { - node.children = this.removeHidden(node.children); - } - return true; - }); - } -} - diff --git a/aio/src/app/sidenav/menu.component.scss b/aio/src/app/sidenav/menu.component.scss deleted file mode 100644 index 8ac7a69556..0000000000 --- a/aio/src/app/sidenav/menu.component.scss +++ /dev/null @@ -1,23 +0,0 @@ -.fill-remaining-space { - flex: 1 1 auto; -} - -.nav-link { - margin-right: 10px; - margin-left: 20px; - cursor: pointer; -} - -@media (max-width: 700px) { - .nav-link { - margin-right: 8px; - margin-left: 0px; - } -} -@media (max-width: 600px) { - .nav-link { - font-size: 80%; - margin-right: 8px; - margin-left: 0px; - } -} diff --git a/aio/src/app/sidenav/menu.component.ts b/aio/src/app/sidenav/menu.component.ts deleted file mode 100644 index 1e66304357..0000000000 --- a/aio/src/app/sidenav/menu.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'aio-menu', - template: ` - Home - - API - News - Features - `, - styleUrls: ['./menu.component.scss'], - animations: [] -}) -export class MenuComponent { -} diff --git a/aio/src/app/sidenav/nav-item.component.html b/aio/src/app/sidenav/nav-item.component.html deleted file mode 100644 index 882228d190..0000000000 --- a/aio/src/app/sidenav/nav-item.component.html +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/aio/src/app/sidenav/nav-item.component.scss b/aio/src/app/sidenav/nav-item.component.scss deleted file mode 100644 index 19ba2a0b86..0000000000 --- a/aio/src/app/sidenav/nav-item.component.scss +++ /dev/null @@ -1,114 +0,0 @@ - -/************************************ - - Media queries - -To use these, put this snippet in the approriate selector: - - @include bp(tiny) { - background-color: purple; - } - - Replace "tiny" with "medium" or "big" as necessary. - -*************************************/ - -@mixin bp($point) { - - $bp-xsmall: "(min-width: 320px)"; - $bp-teeny: "(min-width: 480px)"; - $bp-tiny: "(min-width: 600px)"; - $bp-small: "(min-width: 650px)"; - $bp-medium: "(min-width: 800px)"; - $bp-big: "(min-width: 1000px)"; - - @if $point == big { - @media #{$bp-big} { @content; } - } - @else if $point == medium { - @media #{$bp-medium} { @content; } - } - @else if $point == small { - @media #{$bp-small} { @content; } - } - @else if $point == tiny { - @media #{$bp-tiny} { @content; } - } - @else if $point == teeny { - @media #{$bp-teeny} { @content; } - } - @else if $point == xsmall { - @media #{$bp-xsmall} { @content; } - } -} - -/************************************/ - -.vertical-menu { - padding-left: 0; -} - -a.vertical-menu { - color: #545454; - cursor: pointer; - display: block; - padding-bottom: 10px; - padding-top: 10px; - padding-right: 10px; - text-decoration: none; - text-align: left; - &:hover { - background-color: #ddd; - } -} - -.vertical-menu.selected { - color:#018494; -} - -.heading { - color: #444; - cursor: pointer; - font-size: .85rem; - min-width: 200px; - padding-left: 10px; - position: relative; - text-transform: uppercase; -} - -.material-icons { - display: none; -} - -.material-icons.active { - display: inline-block; - position: absolute; - top: 6px; - // left: 4px; -} - -.heading-children { - display: none; -} - -.heading-children.active { - display: block; -} - - -.heading.selected.level-1, -.heading-children.selected.level-1 { - border-left: 3px #00bcd4 solid; -} - -.level-1 { - padding-left: 10px; -} - -.level-2 { - padding-left: 20px; -} - -.level-3 { - padding-left: 30px; -} diff --git a/aio/src/app/sidenav/nav-item.component.ts b/aio/src/app/sidenav/nav-item.component.ts deleted file mode 100644 index aa6283f715..0000000000 --- a/aio/src/app/sidenav/nav-item.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Component, EventEmitter, Input, OnInit, OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs/Subscription'; - -import { Doc, NavNode } from '../nav-engine'; - -@Component({ - selector: 'aio-navitem', - templateUrl: 'nav-item.component.html', - styleUrls: ['nav-item.component.scss'] -}) -export class NavItemComponent implements OnInit, OnDestroy { - @Input() selectedNode: EventEmitter; - @Input() node: NavNode; - @Input() level = 1; - - isActive = false; - isSelected = false; - isItem = false; - classes: {[index: string]: boolean }; - href = ''; - label = ''; - selectedNodeSubscription: Subscription; - target = ''; - tooltip = ''; - - ngOnInit() { - this.label = this.node.navTitle; - this.tooltip = this.node.tooltip; - this.isItem = this.node.children == null; - this.href = this.node.url || this.node.docPath ; - this.target = this.node.url ? '_blank' : '_self'; - this.setClasses(); - - if (this.selectedNode) { - this.selectedNodeSubscription = this.selectedNode.subscribe((n: NavNode) => { - this.isSelected = n && - ( n === this.node || - (n.ancestorIds && n.ancestorIds.indexOf(this.node.id) > -1) - ); - // this.isActive = this.isSelected; // disabled per meeting Feb 13 - this.setClasses(); - }); - } - } - - ngOnDestroy() { - if (this.selectedNodeSubscription) { - this.selectedNodeSubscription.unsubscribe(); - this.selectedNodeSubscription = null; - } - } - - setClasses() { - this.classes = { - ['level-' + this.level]: true, - active: this.isActive, - selected: this.isSelected - }; - } - - itemClicked() { - this.isActive = true; - this.isSelected = !!this.node.docId; - this.setClasses(); - if (this.isSelected) { - this.selectedNode.emit(this.node); - return false; - } - return !!this.node.url; // let browser handle the external page request. - } - - headerClicked() { - this.isActive = !this.isActive; - if (this.isActive && this.node.docId) { - this.isSelected = true; - if (this.selectedNode) { - this.selectedNode.emit(this.node); - } - } - this.setClasses(); - return false; - } -} diff --git a/aio/src/app/sidenav/sidenav.component.html b/aio/src/app/sidenav/sidenav.component.html deleted file mode 100644 index 8cf111103e..0000000000 --- a/aio/src/app/sidenav/sidenav.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - -
- -
-
diff --git a/aio/src/app/sidenav/sidenav.component.scss b/aio/src/app/sidenav/sidenav.component.scss deleted file mode 100644 index c1577d1036..0000000000 --- a/aio/src/app/sidenav/sidenav.component.scss +++ /dev/null @@ -1,27 +0,0 @@ -.sidenav-container { - width: 100%; - height: 100vh; -} - -.sidenav-content { - height: 100%; - width: 100%; - margin: auto; - padding: 1rem; -} - -.sidenav-content button { - min-width: 50px; -} - -.sidenav { - padding: 0; -} - -md-toolbar { - display: none; - padding-left: 10px !important; -} -md-toolbar.active { - display: block; -} diff --git a/aio/src/app/sidenav/sidenav.component.spec.ts b/aio/src/app/sidenav/sidenav.component.spec.ts deleted file mode 100644 index f845ce3d11..0000000000 --- a/aio/src/app/sidenav/sidenav.component.spec.ts +++ /dev/null @@ -1,223 +0,0 @@ -/* tslint:disable:no-unused-variable */ -import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -import { Component, CUSTOM_ELEMENTS_SCHEMA, DebugElement, EventEmitter, Input, OnInit } from '@angular/core'; - -import { Observable } from 'rxjs/Observable'; -import { of } from 'rxjs/observable/of'; -import 'rxjs/add/operator/delay'; - -import { Doc, DocMetadata, NavEngine, NavMapService, NavMap, NavNode } from '../nav-engine'; -import { SidenavComponent } from './sidenav.component'; - -//// Test Components /// -@Component({ - // tslint:disable-next-line:component-selector - selector: 'md-sidenav', - template: '' -}) -class FakeMdSideNavComponent { - _isOpen = false; - @Input() opened: boolean; - @Input() mode: 'side' | 'over'; - toggle = jasmine.createSpy('toggle'); -} - -@Component({ - selector: 'aio-doc-viewer', - template: '' -}) -class FakeDocViewerComponent { - @Input() doc: Doc; -} - -//// Tests ///// -describe('SidenavComponent', () => { - let component: SidenavComponent; - let fixture: ComponentFixture; - - let fakeDoc: Doc; - let fakeNode: NavNode; - let fakeNavMap: NavMap; - let navEngine: NavEngine; - let navMapService: NavMapService; - let navigateSpy: jasmine.Spy; - - beforeEach(async(() => { - fakeDoc = { - metadata: {docId: 'fake'} as DocMetadata, - content: 'Fake content' - }; - - navEngine = { - currentDoc: of(fakeDoc).delay(0).first(), - navigate: (docId: string) => { } - } as NavEngine; - navigateSpy = spyOn(navEngine, 'navigate'); - - fakeNode = { - id: 42, - docId: fakeDoc.metadata.docId, - navTitle: 'Fakery', - docPath: 'content/fake.hmlt' - } as NavNode; - - fakeNavMap = { - nodes: [fakeNode], - docs: new Map([[fakeNode.docId, fakeNode]]) - }; - - navMapService = { - navMap: of(fakeNavMap).delay(0).first() - } as NavMapService; - - TestBed.configureTestingModule({ - declarations: [ - SidenavComponent, - FakeMdSideNavComponent, - FakeDocViewerComponent - ], - providers: [ - {provide: NavEngine, useValue: navEngine }, - {provide: NavMapService, useValue: navMapService } - ], - schemas: [ CUSTOM_ELEMENTS_SCHEMA ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SidenavComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - describe('#currentDoc', () => { - it('should have "currentDoc" after a tick', fakeAsync(() => { - component.currentDoc.subscribe(doc => { - expect(doc).toBe(fakeDoc); - }); - tick(); - })); - it('should set "currentDocId" as side effect', fakeAsync(() => { - component.currentDoc.subscribe(doc => { - expect(component.currentDocId).toEqual(fakeDoc.metadata.docId); - }); - tick(); - })); - }); - - describe('#nodes', () => { - it('should have "nodes" after a tick', fakeAsync(() => { - component.nodes.subscribe(nodes => { - expect(nodes).toEqual(fakeNavMap.nodes); - }); - tick(); - })); - }); - - describe('#selectedNode', () => { - // Simulate when user clicks a left nav link in a `NavItemComponent` - // which calls `emit` on the selectedNode navigates - // all of this synchronously - it('should call navigate after emitting a node', () => { - expect(navigateSpy.calls.count()).toBe(0, 'before emit'); - component.selectedNode.emit(fakeNode); - expect(navigateSpy.calls.count()).toBe(1, 'after emit'); - }); - - it('should raise event when currentDoc changes', done => { - component.selectedNode.subscribe((node: NavNode) => { - expect(node.docId).toBe(fakeDoc.metadata.docId); - done(); - }); - }); - }); - - describe('#onResize', () => { - it('should go into side-by-side when width > 600', () => { - component.onResize(601); - expect(component.isSideBySide).toBe(true); - }); - - it('should emit overlay mode when width > 600', () => { - component.isOverlayMode.subscribe(isOverlay => - expect(isOverlay).toBe(false) - ); - component.onResize(601); - }); - it('should go into side-by-side when width == 600', () => { - component.onResize(600); - expect(component.isSideBySide).toBe(false); - }); - - it('should emit overlay mode when width == 600', () => { - component.isOverlayMode.subscribe(isOverlay => - expect(isOverlay).toBe(true) - ); - component.onResize(600); - }); - }); - - describe('-> MdSideNav', () => { - - let mdSideNavComponent: FakeMdSideNavComponent; - - beforeEach(() => { - mdSideNavComponent = fixture.debugElement - .query(By.directive(FakeMdSideNavComponent)) - .componentInstance as FakeMdSideNavComponent; - }); - - it('toggle should call through to MdSideNav toggle', () => { - const calls = mdSideNavComponent.toggle.calls; - expect(calls.count()).toBe(0, 'before toggle'); - component.toggle(); - expect(calls.count()).toBe(1, 'after toggle'); - }); - - it('should be opened when width > 600', () => { - component.onResize(601); - fixture.detectChanges(); - expect(mdSideNavComponent.opened).toBe(true); - }); - - it('should be not open when width == 600', () => { - component.onResize(600); - fixture.detectChanges(); - expect(mdSideNavComponent.opened).toBe(false); - }); - }); - - describe('-> DocViewer', () => { - let docViewer: FakeDocViewerComponent; - - beforeEach(() => { - docViewer = fixture.debugElement - .query(By.directive(FakeDocViewerComponent)) - .componentInstance as FakeDocViewerComponent; - }); - - it('should not have a document at the start', () => { - expect(docViewer.doc).toBeNull(); - }); - - // Doesn't work with fakeAsync and async complains about the delay timer (setInterval); - // it('should have a document after NavEngine has a current doc', (fakeAsync(() => { - // tick(); - // fixture.detectChanges(); - // expect(docViewer.doc).toBe(fakeDoc); - // }))); - - // Must go old school with setTimeout and `done` - it('should have a document after NavEngine has a current doc', (done => { - setTimeout(() => { - fixture.detectChanges(); - expect(docViewer.doc).toBe(fakeDoc); - done(); - }, 1); - })); - - }); -}); diff --git a/aio/src/app/sidenav/sidenav.component.ts b/aio/src/app/sidenav/sidenav.component.ts deleted file mode 100644 index cc0d39673e..0000000000 --- a/aio/src/app/sidenav/sidenav.component.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Component, EventEmitter, Output, OnInit, OnChanges, ViewChild } from '@angular/core'; -import { MdSidenav } from '@angular/material/sidenav'; - -import { Observable } from 'rxjs/Observable'; -import 'rxjs/add/operator/do'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/take'; - -import { Doc, NavEngine, NavMap, NavMapService, NavNode } from '../nav-engine'; - -@Component({ - selector: 'aio-sidenav', - templateUrl: './sidenav.component.html', - styleUrls: ['./sidenav.component.scss'], - animations: [] -}) -export class SidenavComponent implements OnInit { - - @Output() isOverlayMode = new EventEmitter(); - @ViewChild('sidenav') private sidenav: MdSidenav; - - currentDoc: Observable; - currentDocId: string; - isSideBySide = false; - nodes: Observable; - selectedNode = new EventEmitter(); - sideBySideWidth = 600; - windowWidth = 0; - - constructor( - private navEngine: NavEngine, - private navMapService: NavMapService ) {} - - ngOnInit() { - this.onResize(window.innerWidth); - - this.nodes = this.navMapService.navMap.map( navMap => navMap.nodes ); - - this.currentDoc = this.navEngine.currentDoc - .do(doc => { - // Side effect: when the current doc changes, - // get its NavNode and alert the navigation panel - this.currentDocId = doc.metadata.docId; - this.navMapService.navMap.first() // take makes sure it completes! - .map(navMap => navMap.docs.get(this.currentDocId)) - .subscribe( node => this.selectedNode.emit(node)); - }); - - this.selectedNode.subscribe((node: NavNode) => { - // Navigate when the user selects a doc other than the current doc - const docId = node && node.docId; - if (docId && docId !== this.currentDocId) { - this.navEngine.navigate(docId); - } - }); - } - - onResize(width) { - this.windowWidth = width; - this.isSideBySide = width > this.sideBySideWidth; - this.sidenav.mode = this.isSideBySide ? 'side' : 'over'; - this.isOverlayMode.emit(!this.isSideBySide); - } - - toggle() { - this.sidenav.toggle(); - } -} diff --git a/aio/src/content/navmap.json b/aio/src/content/navmap.json deleted file mode 100644 index 259a895d56..0000000000 --- a/aio/src/content/navmap.json +++ /dev/null @@ -1,402 +0,0 @@ -{ "nodes": [ - { - "docId": "guide/quickstart", - "navTitle": "Quickstart", - "tooltip": "A quick look at an Angular app." - }, - - { - "docId": "guide/cli-quickstart", - "navTitle": "CLI Quickstart", - "tooltip": "A quick look at an Angular app built with the Angular CLI." - }, - - { - "navTitle": "Tutorial", - "tooltip": "The Tour of Heroes tutorial takes you through the steps of creating an Angular application in TypeScript.", - "children": [ - { - "docId": " tutorial/", - "navTitle": "Introduction", - "tooltip": "Introduction to the Tour of Heroes tutorial" - }, - { - "docId": "tutorial/toh-1", - "navTitle": "The hero editor", - "tooltip": "Build a simple hero editor" - }, - { - "docId": "tutorial/toh-2", - "navTitle": "Master/detail", - "tooltip": "Build a master/detail page with a list of heroes." - }, - { - "docId": "tutorial/toh-3", - "navTitle": "Multiple components", - "tooltip": "Refactor the master/detail view into separate components." - }, - { - "docId": "tutorial/toh-4", - "navTitle": "Services", - "tooltip": "Create a reusable service to manage hero data." - }, - { - "docId": "tutorial/toh-5", - "navTitle": "Routing", - "tooltip": "Add the Angular router and navigate among the views." - }, - { - "docId": "tutorial/toh-6", - "navTitle": "HTTP", - "tooltip": "Use HTTP to retrieve and save hero data." - } - ] - }, - - { - "navTitle": "Getting started", - "tooltip": "A gentle introduction to Angular.", - "children": [ - { - "docId": "guide/docs-overview", - "navTitle": "Overview", - "tooltip": "How to read and use this documentation." - }, - { - "docId": "guide/setup", - "navTitle": "Setup", - "tooltip": "Install the Angular QuickStart seed for faster, more efficient development on your machine." - }, - - { - "docId": "guide/learning-angular", - "navTitle": "Learning Angular", - "tooltip": "A suggested path through the documentation for Angular newcomers." - }, - - { - "docId": "guide/architecture", - "navTitle": "Architecture", - "tooltip": "The basic building blocks of Angular applications." - }, - - { - "docId": "guide/appmodule", - "navTitle": "The root AppModule", - "tooltip": "Tell Angular how to construct and bootstrap the app in the root \"AppModule\"." - }, - - { - "docId": "guide/displaying-data", - "navTitle": "Displaying data", - "tooltip": "Property binding helps show app data in the UI." - }, - - { - "docId": "guide/user-input", - "navTitle": "User Input", - "tooltip": "User input triggers DOM events. We listen to those events with event bindings that funnel updated values back into our components and models." - }, - - { - "docId": "guide/forms", - "navTitle": "Forms", - "tooltip": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors." - }, - - { - "docId": "guide/dependency-injection", - "navTitle": "Dependency Injection", - "tooltip": "Angular's dependency injection system creates and delivers dependent services \"just-in-time\"." - }, - - { - "docId": "guide/template-syntax", - "navTitle": "Template Syntax", - "tooltip": "Learn how to write templates that display data and consume user events with the help of data binding." - }, - - { - "docId": "guide/cheatsheet", - "navTitle": "Cheat Sheet", - "tooltip": "A quick guide to common Angular coding techniques." - }, - - { - "docId": "guide/style-guide", - "navTitle": "Style guide", - "tooltip": "Write Angular with style." - }, - - { - "docId": "guide/glossary", - "navTitle": "Glossary", - "tooltip": "Brief definitions of the most important words in the Angular vocabulary." - }, - - { - "docId": "guide/change-log", - "navTitle": "Change Log", - "tooltip": "An annotated history of recent documentation improvements." - } - ]}, - - { - "navTitle": "Core", - "tooltip": "Learn the core capabilities of Angular", - "children": [ - { - "navTitle": "Angular Modules", - "tooltip": "Learn how directives modify the layout and behavior of elements.", - "children": [ - { - "docId": "guide/ngmodule", - "navTitle": "NgModule", - "tooltip": "Define application modules with @NgModule." - }, - - { - "docId": "guide/ngmodule-faq", - "navTitle": "Angular module FAQs", - "tooltip": "Answers to frequently asked questions about @NgModule." - } - ]}, - - { - "docId": "guide/component-communication", - "navTitle": "Component interaction", - "tooltip": "Share information between different directives and components." - }, - - { - "docId": "guide/component-relative-paths", - "navTitle": "Component-relative paths", - "tooltip": "Use relative URLs for component templates and styles." - }, - - { - "navTitle": "Dependency Injection", - "tooltip": "More about Dependency Injection", - "children": [ - { - "docId": "guide/cb-dependency-injection", - "navTitle": "Dependency injection", - "tooltip": "Techniques for Dependency Injection." - }, - - { - "docId": "guide/hierarchical-dependency-injection", - "navTitle": "Hierarchical injectors", - "tooltip": "Angular's hierarchical dependency injection system supports nested injectors in parallel with the component tree." - } - ]}, - - { - "docId": "guide/dynamic-component-loader", - "navTitle": "Dynamic components", - "tooltip": "Load components dynamically." - }, - - { - "docId": "guide/directives", - "navTitle": "Directives", - "tooltip": "Learn how directives modify the layout and behavior of elements.", - "children": [ - { - "docId": "guide/attribute-directives", - "navTitle": "Attribute directives", - "tooltip": "Attribute directives attach behavior to elements." - }, - { - "docId": "guide/structural-directives", - "navTitle": "Structural directives", - "tooltip": "Structural directives manipulate the layout of the page." - } - ] - }, - - { - "navTitle": "Forms", - "tooltip": "More about forms", - "children": [ - { - "docId": "guide/dynamic-form", - "navTitle": "Dynamic forms", - "tooltip": "Render dynamic forms with FormGroup." - }, - - { - "docId": "guide/form-validation", - "navTitle": "Form validation", - "tooltip": "Validate user's form entries." - }, - - { - "docId": "guide/reactive-forms", - "navTitle": "Reactive forms", - "tooltip": "Create a reactive form using FormBuilder, groups, and arrays." - } - ]}, - - { - "docId": "guide/server-communication", - "navTitle": "HTTP client", - "tooltip": "Use an HTTP Client to talk to a remote server." - }, - - { - "docId": "guide/lifecycle-hooks", - "navTitle": "Lifecycle hooks", - "tooltip": "Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them." - }, - - { - "docId": "guide/pipes", - "navTitle": "Pipes", - "tooltip": "Pipes transform displayed values within a template." - }, - - { - "docId": "guide/router", - "navTitle": "Routing & navigation", - "tooltip": "Discover the basics of screen navigation with the Angular Router." - } - ]}, - - { - "navTitle": "Additional Techniques", - "tooltip": "Other", - "children": [ - { - "docId": "guide/aot-compiler", - "navTitle": "Ahead-of-Time compilation", - "tooltip": "Learn why and how to use the Ahead-of-Time (AOT) compiler." - }, - - { - "docId": "guide/animations", - "navTitle": "Animations", - "tooltip": "A guide to Angular's animation system." - }, - - { - "docId": "guide/ajs-quick-reference", - "navTitle": "AngularJS to Angular", - "tooltip": "Learn how AngularJS concepts and techniques map to Angular." - }, - - { - "docId": "guide/component-styles", - "navTitle": "Component styles", - "tooltip": "Learn how to apply CSS styles to components." - }, - - { - "docId": "guide/deployment", - "navTitle": "Deployment", - "tooltip": "Learn how to deploy your Angular app." - }, - - { - "docId": "guide/i18n", - "navTitle": "Internationalization (i18n)", - "tooltip": "Translate the app's template text into multiple languages." - }, - - { - "docId": "guide/security", - "navTitle": "Security", - "tooltip": "Developing for content security in Angular applications." - }, - - { - "navTitle": "Setup", - "tooltip": "Details of the local development setup", - "children": [ - { - "docId": "guide/setup-systemjs-anatomy", - "navTitle": "Setup Anatomy", - "tooltip": "Inside the local development environment for SystemJS." - }, - - { - "docId": "guide/browser-support", - "navTitle": "Browser support", - "tooltip": "Browser support and polyfills guide." - }, - - { - "docId": "guide/npm-packages", - "navTitle": "Npm packages", - "tooltip": "Recommended npm packages, and how to specify package dependencies." - }, - - { - "docId": "guide/typescript-configuration", - "navTitle": "TypeScript configuration", - "tooltip": "TypeScript configuration for Angular developers." - } - ]}, - - { - "docId": "guide/testing", - "navTitle": "Testing", - "tooltip": "Techniques and practices for testing an Angular app." - }, - - { - "docId": "guide/upgrade", - "navTitle": "Upgrading from AngularJS", - "tooltip": "Incrementally upgrade an AngularJS application to Angular." - }, - - { - "docId": "guide/ts-to-js", - "navTitle": "TypeScript to JavaScript", - "tooltip": "Convert Angular TypeScript examples into ES6 and ES5 JavaScript." - }, - - { - "docId": "guide/visual-studio-2015", - "navTitle": "Visual Studio 2015 QuickStart", - "tooltip": "Use Visual Studio 2015 with the QuickStart files." - }, - - { - "docId": "guide/webpack", - "navTitle": "Webpack: an introduction", - "tooltip": "Create Angular applications with a Webpack based tooling." - } - ] - }, - - { - "docId": "resources/", - "navTitle": "Resources", - "children": [ - { - "docId": "about", - "navTitle": "About", - "tooltip": "The people behind Angular." - } - ] - }, - - { - "navTitle": "Help", - "children": [ - { - "url": - "http://stackoverflow.com/questions/tagged/angular2", - "urlNew": "http://stackoverflow.com/questions/tagged/angular2.html", - "navTitle": "Stack Overflow", - "tooltip": "Stack Overflow: where the community answers your technical Angular questions." - }, - { - "url": "https://gitter.im/angular/angular", - "navTitle": "Gitter", - "tooltip": "Chat about Angular with other birds of a feather." - } - ] - } -]}