Skip to content

Commit

Permalink
chore: added button overview
Browse files Browse the repository at this point in the history
  • Loading branch information
pimenovoleg committed Jun 24, 2019
1 parent b8f4450 commit ef81da5
Show file tree
Hide file tree
Showing 16 changed files with 933 additions and 7 deletions.
2 changes: 1 addition & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
{
"glob": "**/*",
"input": "./node_modules/@ptsecurity/mosaic-examples/docs-content",
"input": "./dist/docs-content",
"output": "/docs-content"
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
Overview for Component
{{componentViewer.componentDocItem.packageName}}/{{componentViewer.componentDocItem.id}}
<doc-viewer
documentUrl="/docs-content/overviews/{{componentViewer.componentDocItem.packageName}}/{{componentViewer.componentDocItem.id}}.html"
>

</doc-viewer>
<table-of-contents #toc container=".mat-drawer-content"></table-of-contents>
Original file line number Diff line number Diff line change
@@ -1,13 +1,50 @@
import { Component, ViewEncapsulation } from '@angular/core';
import {Component, OnDestroy, ViewChild, ViewEncapsulation} from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import {combineLatest, Subject} from 'rxjs';
import {map, takeUntil} from 'rxjs/operators';

import { DocItem, DocumentationItems } from '../../shared/documentation-items/documentation-items';
import { TableOfContents } from '../../shared/table-of-contents/table-of-contents';


@Component({
selector: 'docs-component-viewer',
templateUrl: './component-viewer.template.html',
encapsulation: ViewEncapsulation.None
})
export class ComponentViewerComponent {
export class ComponentViewerComponent implements OnDestroy {

componentDocItem: DocItem;
sections: Set<string> = new Set(['overview', 'api']);
private _destroyed = new Subject();

constructor(_route: ActivatedRoute,
private router: Router,
public docItems: DocumentationItems
) {
// Listen to changes on the current route for the doc id (e.g. button/checkbox) and the
// parent route for the section (material/cdk).
combineLatest(_route.params, _route.parent.params).pipe(
map((p: [Params, Params]) => ({id: p[0].id, section: p[1].section})),
map((p) => ({doc: docItems.getItemById(p.id, p.section), section: p.section}),
takeUntil(this._destroyed))
).subscribe((d) => {
this.componentDocItem = d.doc;

if (this.componentDocItem) {
console.log(this.componentDocItem.name);
this.componentDocItem.examples.length ?
this.sections.add('examples') :
this.sections.delete('examples');
} else {
//this.router.navigate(['/' + d.section]);
}
});
}

ngOnDestroy(): void {
this._destroyed.next();
}
}


Expand All @@ -18,6 +55,11 @@ export class ComponentViewerComponent {
})
export class ComponentOverviewComponent {

@ViewChild('toc', {static: false}) tableOfContents: TableOfContents;

constructor(public componentViewer: ComponentViewerComponent) {

}
}

@Component({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { McTabsModule } from '@ptsecurity/mosaic/tabs';

import { DocViewerModule } from '../../shared/doc-viewer/doc-viewer-module';
import { DocumentationItems } from '../../shared/documentation-items/documentation-items';
import { TableOfContentsModule } from '../../shared/table-of-contents/table-of-contents.module';

import {
ComponentApiComponent,
ComponentOverviewComponent,
Expand All @@ -14,8 +18,9 @@ import {
imports: [
McTabsModule,
RouterModule,
// DocViewerModule,
CommonModule
DocViewerModule,
CommonModule,
TableOfContentsModule
],
exports: [
ComponentViewerComponent
Expand All @@ -25,6 +30,6 @@ import {
ComponentOverviewComponent,
ComponentApiComponent
],
providers: []
providers: [DocumentationItems]
})
export class ComponentViewerModule {}
26 changes: 26 additions & 0 deletions packages/docs/src/app/shared/doc-viewer/doc-viewer-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { PortalModule } from '@ptsecurity/cdk/portal';
import { McButtonModule } from '@ptsecurity/mosaic/button';
import { McTabsModule } from '@ptsecurity/mosaic/tabs';

import { CopierService } from '../copier/copier.service';
import { ExampleViewer } from '../example-viewer/example-viewer';

import { DocViewer } from './doc-viewer';


// ExampleViewer is included in the DocViewerModule because they have a circular dependency.
@NgModule({
imports: [
McButtonModule,
McTabsModule,
CommonModule,
PortalModule
],
providers: [CopierService],
declarations: [DocViewer, ExampleViewer],
entryComponents: [ExampleViewer],
exports: [DocViewer, ExampleViewer]
})
export class DocViewerModule { }
130 changes: 130 additions & 0 deletions packages/docs/src/app/shared/doc-viewer/doc-viewer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import {
ApplicationRef,
Component,
ComponentFactoryResolver,
ElementRef,
EventEmitter,
Injector,
Input,
NgZone,
OnDestroy,
Output,
SecurityContext,
ViewContainerRef
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { ComponentPortal, DomPortalHost } from '@ptsecurity/cdk/portal';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';

import { ExampleViewer } from '../example-viewer/example-viewer';


@Component({
selector: 'doc-viewer',
template: 'Loading document...'
})
export class DocViewer implements OnDestroy {

/** The URL of the document to display. */
@Input()
set documentUrl(url: string) {
this._fetchDocument(url);
}

@Output() contentRendered = new EventEmitter<void>();

/** The document text. It should not be HTML encoded. */
textContent = '';
private _portalHosts: DomPortalHost[] = [];
private _documentFetchSubscription: Subscription;

constructor(private _appRef: ApplicationRef,
private _componentFactoryResolver: ComponentFactoryResolver,
private _elementRef: ElementRef,
private _http: HttpClient,
private _injector: Injector,
private _viewContainerRef: ViewContainerRef,
private _ngZone: NgZone,
private _domSanitizer: DomSanitizer) {
}

ngOnDestroy() {
this._clearLiveExamples();

if (this._documentFetchSubscription) {
this._documentFetchSubscription.unsubscribe();
}
}

/** Fetch a document by URL. */
private _fetchDocument(url: string) {
// Cancel previous pending request
if (this._documentFetchSubscription) {
this._documentFetchSubscription.unsubscribe();
}

this._documentFetchSubscription = this._http.get(url, {responseType: 'text'}).subscribe(
(document) => this.updateDocument(document),
(error) => this.showError(url, error)
);
}

/**
* Updates the displayed document.
* @param rawDocument The raw document content to show.
*/
private updateDocument(rawDocument: string) {
// Replace all relative fragment URLs with absolute fragment URLs. e.g. "#my-section" becomes
// "/components/button/api#my-section". This is necessary because otherwise these fragment
// links would redirect to "/#my-section".
rawDocument = rawDocument.replace(/href="#([^"]*)"/g, (_m: string, fragmentUrl: string) => {
const absoluteUrl = `${location.pathname}#${fragmentUrl}`;

return `href="${this._domSanitizer.sanitize(SecurityContext.URL, absoluteUrl)}"`;
});

// tslint:disable-next-line:no-inner-html
this._elementRef.nativeElement.innerHTML = rawDocument;
this.textContent = this._elementRef.nativeElement.textContent;

this._loadComponents('mosaic-docs-example', ExampleViewer);

// Resolving and creating components dynamically in Angular happens synchronously, but since
// we want to emit the output if the components are actually rendered completely, we wait
// until the Angular zone becomes stable.
this._ngZone.onStable
.pipe(take(1))
.subscribe(() => this.contentRendered.next());
}

/** Show an error that occurred when fetching a document. */
private showError(url: string, error: HttpErrorResponse) {
console.log(error);
this._elementRef.nativeElement.innerText =
`Failed to load document: ${url}. Error: ${error.statusText}`;
}

/** Instantiate a ExampleViewer for each example. */
private _loadComponents(componentName: string, componentClass: any) {
const exampleElements =
this._elementRef.nativeElement.querySelectorAll(`[${componentName}]`);

Array.prototype.slice.call(exampleElements).forEach((element: Element) => {
const example = element.getAttribute(componentName);
const portalHost = new DomPortalHost(
element, this._componentFactoryResolver, this._appRef, this._injector);
const examplePortal = new ComponentPortal(componentClass, this._viewContainerRef);
const exampleViewer = portalHost.attach(examplePortal);
(exampleViewer.instance as ExampleViewer).example = example;

this._portalHosts.push(portalHost);
});
}

private _clearLiveExamples() {
this._portalHosts.forEach((h) => h.dispose());
this._portalHosts = [];
}
}
Loading

0 comments on commit ef81da5

Please sign in to comment.