Skip to content

Commit

Permalink
fix(app): navigation links do not work when using baseHref
Browse files Browse the repository at this point in the history
Closes #34
  • Loading branch information
skoropadas committed Mar 22, 2023
1 parent 8618d77 commit 41f4c3f
Show file tree
Hide file tree
Showing 17 changed files with 125 additions and 81 deletions.
2 changes: 1 addition & 1 deletion apps/ng-doc/src/app/docs/ng-doc.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const api: NgDocApi = {
scopes: [
{
name: '@ng-doc/app',
route: 'app',
route: 'my-site',
include: 'libs/app/**/*.ts',
},
{
Expand Down
1 change: 1 addition & 0 deletions libs/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from '@ng-doc/app/components/kind-icon';
export * from '@ng-doc/app/components/link';
export * from '@ng-doc/app/components/navbar';
export * from '@ng-doc/app/components/page';
export * from '@ng-doc/app/components/page-link';
export * from '@ng-doc/app/components/playground';
export * from '@ng-doc/app/components/root';
export * from '@ng-doc/app/components/search';
Expand Down
2 changes: 2 additions & 0 deletions libs/app/components/page-link/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './page-link.component';
export * from './page-link.module';
5 changes: 5 additions & 0 deletions libs/app/components/page-link/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"lib": {
"entryFile": "index.ts"
}
}
Empty file.
11 changes: 11 additions & 0 deletions libs/app/components/page-link/page-link.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<a [class]="classes" [routerLink]="path" [fragment]="fragment" *ngIf="!isExternalLink">
<ng-container *ngTemplateOutlet="content"></ng-container>
</a>

<a [class]="classes" [href]="path" *ngIf="isExternalLink" target="_blank">
<ng-container *ngTemplateOutlet="content"></ng-container>
</a>

<ng-template #content>
<ng-content></ng-content>
</ng-template>
27 changes: 27 additions & 0 deletions libs/app/components/page-link/page-link.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {ChangeDetectionStrategy, Component, HostBinding, Input} from '@angular/core';

@Component({
selector: 'ng-doc-page-link',
templateUrl: './page-link.component.html',
styleUrls: ['./page-link.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NgDocPageLinkComponent {
@Input()
href: string = '';

@Input()
classes: string = '';

get isExternalLink(): boolean {
return this.href.startsWith('http');
}

get path(): string {
return this.href.split('#')[0];
}

get fragment(): string {
return this.href.split('#')[1];
}
}
12 changes: 12 additions & 0 deletions libs/app/components/page-link/page-link.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {RouterLink} from '@angular/router';

import {NgDocPageLinkComponent} from './page-link.component';

@NgModule({
declarations: [NgDocPageLinkComponent],
imports: [CommonModule, RouterLink],
exports: [NgDocPageLinkComponent],
})
export class NgDocPageLinkModule {}
1 change: 1 addition & 0 deletions libs/app/components/page/page.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
ngDocIconProcessor
ngDocTooltipProcessor
ngDocPlaygroundProcessor
ngDocLinkProcessor
#pageContainer
></div>

Expand Down
2 changes: 2 additions & 0 deletions libs/app/components/page/page.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
NgDocCodeProcessorModule,
NgDocDemoProcessorModule,
NgDocIconProcessorModule,
NgDocLinkProcessorModule,
NgDocPlaygroundProcessorModule,
NgDocTooltipProcessorModule,
} from '@ng-doc/app/processors';
Expand Down Expand Up @@ -53,6 +54,7 @@ import {NgDocPageComponent} from './page.component';
RouterLink,
NgDocButtonModule,
NgDocTextModule,
NgDocLinkProcessorModule,
],
exports: [NgDocPageComponent],
})
Expand Down
75 changes: 3 additions & 72 deletions libs/app/components/root/root.component.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import {BreakpointObserver} from '@angular/cdk/layout';
import {DOCUMENT, Location} from '@angular/common';
import {ChangeDetectionStrategy, Component, Directive, ElementRef, Inject, NgZone} from '@angular/core';
import {Router} from '@angular/router';
import {isExternalLink} from '@ng-doc/app/helpers/is-external-link';
import {ChangeDetectionStrategy, Component, Directive} from '@angular/core';
import {NgDocSidebarService} from '@ng-doc/app/services/sidebar';
import {fadeAnimation} from '@ng-doc/ui-kit/animations';
import {ngDocZoneDetach} from '@ng-doc/ui-kit/observables';
import {WINDOW} from '@ng-web-apis/common';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {fromEvent, Observable} from 'rxjs';
import {filter} from 'rxjs/operators';
import {UntilDestroy} from '@ngneat/until-destroy';

/**
* Directive uses for providing custom navbar, you should mark element with this directive
Expand Down Expand Up @@ -57,66 +49,5 @@ export class NgDocCustomSidebarDirective {}
})
@UntilDestroy()
export class NgDocRootComponent {
constructor(
@Inject(DOCUMENT)
private readonly document: Document,
private readonly elementRef: ElementRef<HTMLElement>,
private readonly ngZone: NgZone,
private readonly router: Router,
private readonly location: Location,
private readonly breakpointObserver: BreakpointObserver,
protected readonly sidebarService: NgDocSidebarService,
@Inject(WINDOW)
private readonly window: Window,
) {
(
fromEvent(this.elementRef.nativeElement, 'click').pipe(
filter(this.isPointerEvent),
untilDestroyed(this),
ngDocZoneDetach(this.ngZone),
) as Observable<PointerEvent>
).subscribe((event: PointerEvent) => {
if (event.target instanceof Node) {
let target: Node | null = event.target;

while (target && !(target instanceof HTMLAnchorElement)) {
target = target.parentElement;
}

if (target instanceof HTMLAnchorElement) {
const base: HTMLBaseElement | null = this.document.querySelector('base');
const baseHref: string = base?.getAttribute('href') ?? '/';

if (isExternalLink(target.href)) {
event.preventDefault();

this.window.open(target.href, '_blank')?.focus();
} else {
const hasModifier: boolean = event.button !== 0 || event.ctrlKey || event.metaKey;
const isDownloadable: boolean = target.getAttribute('download') != null;

if (!hasModifier && !isDownloadable) {
const {pathname, search} = target;
const isInPageAnchor: boolean = target.getAttribute('href')?.startsWith('#') ?? false;
const correctPathname: string = isInPageAnchor ? this.location.path() : pathname;
const relativeUrl: string = (correctPathname + search).replace(baseHref, '');
const hash: string = target.hash;

event.preventDefault();

this.ngZone.run(() => {
this.router.navigate([relativeUrl], {
fragment: hash.replace(/^#/, '') || undefined,
});
});
}
}
}
}
});
}

private isPointerEvent(event: Event): event is PointerEvent {
return event instanceof PointerEvent;
}
constructor(protected readonly sidebarService: NgDocSidebarService) {}
}
25 changes: 17 additions & 8 deletions libs/app/components/toc/toc.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,16 @@ export class NgDocTocComponent implements OnChanges, AfterViewInit {
) {}

ngOnChanges(): void {
if (this.pageContainer) {
this.map = generateToc(this.pageContainer);
}
/**
* We need to use `Promise.resolve().then()` here because we need to wait for the `pageContainer` to be rendered
* and processed by the processors
*/
Promise.resolve().then(() => {
if (this.pageContainer) {
this.map = generateToc(this.pageContainer);
this.changeDetectorRef.detectChanges();
}
});
}

ngAfterViewInit(): void {
Expand All @@ -80,8 +87,8 @@ export class NgDocTocComponent implements OnChanges, AfterViewInit {
const routerSelection: Observable<NgDocTocItem> = this.router.events.pipe(
map((event: REvent) => {
if (event instanceof Scroll) {
const item: NgDocTocItem | undefined = this.map.find(
(item: NgDocTocItem) => event.routerEvent.url === item.path,
const item: NgDocTocItem | undefined = this.map.find((item: NgDocTocItem) =>
item.path.includes(event.routerEvent.url),
);

if (item) {
Expand All @@ -95,9 +102,11 @@ export class NgDocTocComponent implements OnChanges, AfterViewInit {
debounceTime(20),
);

merge(scrollSelection, routerSelection)
.pipe(distinctUntilChanged(), ngDocZoneOptimize(this.ngZone))
.subscribe(this.select.bind(this));
Promise.resolve().then(() => {
merge(scrollSelection, routerSelection)
.pipe(distinctUntilChanged(), ngDocZoneOptimize(this.ngZone))
.subscribe(this.select.bind(this));
});
}

private select(item: NgDocTocItem): void {
Expand Down
1 change: 1 addition & 0 deletions libs/app/processors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export * from '@ng-doc/app/processors/code-processor';
export * from '@ng-doc/app/processors/demo-processor';
export * from '@ng-doc/app/processors/html-processor';
export * from '@ng-doc/app/processors/icon-processor';
export * from '@ng-doc/app/processors/link-processor';
export * from '@ng-doc/app/processors/playground-processor';
export * from '@ng-doc/app/processors/tooltip-processor';
2 changes: 2 additions & 0 deletions libs/app/processors/link-processor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './link-processor.directive';
export * from './link-processor.module';
26 changes: 26 additions & 0 deletions libs/app/processors/link-processor/link-processor.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Directive, ElementRef, ViewContainerRef} from '@angular/core';
import {NgDocPageLinkComponent} from '@ng-doc/app/components/page-link';
import {NgDocProcessorOptions} from '@ng-doc/app/interfaces';
import {NgDocHtmlProcessor} from '@ng-doc/app/processors/html-processor';

@Directive({
selector: '[ngDocLinkProcessor]',
})
export class NgDocLinkProcessorDirective extends NgDocHtmlProcessor<NgDocPageLinkComponent> {
constructor(
protected override readonly elementRef: ElementRef<HTMLElement>,
protected override readonly viewContainerRef: ViewContainerRef,
) {
super(elementRef, viewContainerRef, `a`, NgDocPageLinkComponent);
}

protected override extractComponentOptions(element: Element): NgDocProcessorOptions<NgDocPageLinkComponent> {
return {
inputs: {
href: element.getAttribute('href') ?? '',
classes: element.getAttribute('class') ?? '',
},
content: [Array.from(element.childNodes)],
};
}
}
9 changes: 9 additions & 0 deletions libs/app/processors/link-processor/link-processor.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {NgModule} from '@angular/core';

import {NgDocLinkProcessorDirective} from './link-processor.directive';

@NgModule({
declarations: [NgDocLinkProcessorDirective],
exports: [NgDocLinkProcessorDirective],
})
export class NgDocLinkProcessorModule {}
5 changes: 5 additions & 0 deletions libs/app/processors/link-processor/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"lib": {
"entryFile": "index.ts"
}
}

0 comments on commit 41f4c3f

Please sign in to comment.