From 5599f53ff87b4c8e3941717e33a554047b973823 Mon Sep 17 00:00:00 2001 From: Ryan Naddy Date: Mon, 11 Mar 2024 20:23:22 -0500 Subject: [PATCH 1/5] added routerLink support --- .vscode/settings.json | 4 +- .../cheat-sheet/cheat-sheet.component.html | 21 +++++- demo/src/app/cheat-sheet/remote/links.md | 21 +++++- lib/src/markdown.component.ts | 66 ++++++++++++++++++- 4 files changed, 103 insertions(+), 9 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4178f74e..1493f9a5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.codeActionsOnSave": { - "source.fixAll": true + "source.fixAll": "explicit" }, "files.associations": { @@ -17,4 +17,4 @@ "typescript.tsdk": "node_modules\\typescript\\lib", "vsicons.presets.angular": true -} \ No newline at end of file +} diff --git a/demo/src/app/cheat-sheet/cheat-sheet.component.html b/demo/src/app/cheat-sheet/cheat-sheet.component.html index 8becb04c..0798c5cf 100644 --- a/demo/src/app/cheat-sheet/cheat-sheet.component.html +++ b/demo/src/app/cheat-sheet/cheat-sheet.component.html @@ -2,7 +2,9 @@

Cheat Sheet

- The following examples are intended as a quick markdown reference and showcase. It is based on Adam Pritchard work of [Markdown Cheat Sheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). + The following examples are intended as a quick markdown reference and + showcase. It is based on Adam Pritchard work of [Markdown Cheat + Sheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
@@ -29,7 +31,20 @@

Lists

{{ links$ | async }}
- +
@@ -61,4 +76,4 @@

Horizontal Rule

{{ horizontalRule$ | async }}
- \ No newline at end of file + diff --git a/demo/src/app/cheat-sheet/remote/links.md b/demo/src/app/cheat-sheet/remote/links.md index 4d6cd1f5..38083deb 100644 --- a/demo/src/app/cheat-sheet/remote/links.md +++ b/demo/src/app/cheat-sheet/remote/links.md @@ -10,6 +10,25 @@ There are two ways to create links. [You can use numbers for reference-style link definitions][1] +[I'm a router link](routerLink:/get-started) + +```md +[I'm a router link](routerLink:/path/to/page) +``` + +```html + +``` + Or leave it empty and use the [link text itself]. URLs and URLs in angle brackets will automatically get turned into links. @@ -20,4 +39,4 @@ Some text to show that the reference links can follow later. [arbitrary case-insensitive reference text]: https://www.mozilla.org [1]: http://slashdot.org -[link text itself]: http://www.reddit.com \ No newline at end of file +[link text itself]: http://www.reddit.com diff --git a/lib/src/markdown.component.ts b/lib/src/markdown.component.ts index 3a275dcc..f0d4e1d0 100644 --- a/lib/src/markdown.component.ts +++ b/lib/src/markdown.component.ts @@ -1,27 +1,40 @@ +import { CommonModule } from '@angular/common'; import { AfterViewInit, Component, ElementRef, EventEmitter, + HostListener, Input, OnChanges, OnDestroy, + Optional, Output, TemplateRef, Type, ViewContainerRef, } from '@angular/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { NavigationExtras, Router } from '@angular/router'; +import { from, merge, Subject } from 'rxjs'; +import { filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; import { KatexOptions } from './katex-options'; import { MarkdownService, ParseOptions, RenderOptions } from './markdown.service'; import { MermaidAPI } from './mermaid-options'; import { PrismPlugin } from './prism-plugin'; +export interface MarkdownRouterLinkOptions { + global?: NavigationExtras; + paths?: { [path: string]: NavigationExtras | undefined }; +} + @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'markdown, [markdown]', - template: '', + template: ` + + + `, + imports: [CommonModule], standalone: true, }) export class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy { @@ -97,12 +110,57 @@ export class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy { @Input() prompt: string | undefined; @Input() output: string | undefined; @Input() user: string | undefined; + @Input() routerLinkOptions: MarkdownRouterLinkOptions | undefined; // Event emitters @Output() error = new EventEmitter(); @Output() load = new EventEmitter(); @Output() ready = new EventEmitter(); + private changed = new Subject(); + /** + * When the markdown content is ready, or when the markdown content changes, this observable emits. + * - Get all the anchor tags in the markdown content. + * - Filter the anchor tags that have a `href` attribute that starts with `/routerLink:`. + * - Set the `data-routerLink` attribute to the `href` attribute without the `/routerLink:` prefix. + * - Remove the `/routerLink:` prefix from the `href` attribute. + */ + protected changed$ = merge(this.ready, this.changed).pipe( + map(() => this.element.nativeElement.querySelectorAll('a')), + switchMap(links => from(links)), + filter(link => link.getAttribute('href')?.startsWith('/routerLink:') === true), + tap(link => link.setAttribute('data-routerLink', link.getAttribute('href')!.replace('/routerLink:', ''))), + tap(link => link.setAttribute('href', link.getAttribute('href')!.replace('/routerLink:', ''))), + ); + + @HostListener('click', ['$event']) + onDocumentClick(event: MouseEvent) { + const target = event.target as HTMLElement; + const anchor = target.nodeName.toLowerCase() === 'a' ? target : target.closest('a'); + const path = anchor?.getAttribute('href'); + if (path && anchor) { + // Stop the browser from navigating + event.preventDefault(); + event.stopPropagation(); + + // Get the routerLink commands to navigate to + const commands = anchor.getAttribute('data-routerLink')!.split('/').filter(String); + + let extras: NavigationExtras | undefined; + // Find the path in the routerLinkOptions + if (this.routerLinkOptions?.paths) { + extras = this.routerLinkOptions.paths[path]; + } + // Get the global options if no path was found + if (!extras && this.routerLinkOptions?.global) { + extras = this.routerLinkOptions.global; + } + + // Navigate to the path using the router service + this.router?.navigate(commands, extras); + } + } + private _clipboard = false; private _commandLine = false; private _disableSanitizer = false; @@ -119,10 +177,12 @@ export class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy { public element: ElementRef, public markdownService: MarkdownService, public viewContainerRef: ViewContainerRef, + @Optional() public router?: Router, ) { } ngOnChanges(): void { this.loadContent(); + this.changed.next(); } loadContent(): void { From 128b9984aee0a2b7b591a8a1b381e7f05f45e563 Mon Sep 17 00:00:00 2001 From: Ryan Naddy Date: Mon, 11 Mar 2024 20:27:44 -0500 Subject: [PATCH 2/5] fix formatting --- .vscode/settings.json | 2 +- demo/src/app/cheat-sheet/cheat-sheet.component.html | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1493f9a5..dc38716e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.codeActionsOnSave": { - "source.fixAll": "explicit" + "source.fixAll": true }, "files.associations": { diff --git a/demo/src/app/cheat-sheet/cheat-sheet.component.html b/demo/src/app/cheat-sheet/cheat-sheet.component.html index 0798c5cf..67e57da1 100644 --- a/demo/src/app/cheat-sheet/cheat-sheet.component.html +++ b/demo/src/app/cheat-sheet/cheat-sheet.component.html @@ -2,9 +2,7 @@

Cheat Sheet

- The following examples are intended as a quick markdown reference and - showcase. It is based on Adam Pritchard work of [Markdown Cheat - Sheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). + The following examples are intended as a quick markdown reference and showcase. It is based on Adam Pritchard work of [Markdown Cheat Sheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
From 2ce3e876c810c7b6d677cb5be0a7e6946fcbfc1a Mon Sep 17 00:00:00 2001 From: Ryan Naddy Date: Mon, 11 Mar 2024 20:28:28 -0500 Subject: [PATCH 3/5] fix formatting --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index dc38716e..4178f74e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,4 +17,4 @@ "typescript.tsdk": "node_modules\\typescript\\lib", "vsicons.presets.angular": true -} +} \ No newline at end of file From 9fd05a0de569dadd594a85d95769773a937ed273 Mon Sep 17 00:00:00 2001 From: Ryan Naddy Date: Mon, 11 Mar 2024 20:30:32 -0500 Subject: [PATCH 4/5] fix formatting --- demo/src/app/cheat-sheet/remote/links.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/demo/src/app/cheat-sheet/remote/links.md b/demo/src/app/cheat-sheet/remote/links.md index 38083deb..ede829cb 100644 --- a/demo/src/app/cheat-sheet/remote/links.md +++ b/demo/src/app/cheat-sheet/remote/links.md @@ -12,10 +12,6 @@ There are two ways to create links. [I'm a router link](routerLink:/get-started) -```md -[I'm a router link](routerLink:/path/to/page) -``` - ```html + `, imports: [CommonModule],