Skip to content

Commit

Permalink
Merge pull request #70 from fsegurai/development
Browse files Browse the repository at this point in the history
Development merge
  • Loading branch information
fsegurai authored Nov 6, 2024
2 parents b17a6e6 + acc5faf commit 474cbc9
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ on:
branches: [ "main" ]
paths:
- '**'
- '.github/workflows/*.yml'
- "!package.json"
- '!.github/**'
- '!*.yml'
- '!*.config'
- '!*.md'
- '.github/workflows/*.yml'
workflow_dispatch:
inputs: { }

Expand Down
20 changes: 13 additions & 7 deletions .github/workflows/pr_triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,18 @@ jobs:
if (!assignees.includes(assignee)) {
if (assignee.includes('bot')) {
assignee = 'fsegurai';
await github.rest.pulls.requestReviewers({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
reviewers: ['fsegurai']
});
} else {
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
assignees: [assignee]
});
}
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
assignees: [assignee]
});
}
6 changes: 6 additions & 0 deletions .github/workflows/release-demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ permissions:

jobs:
build:
if: |
github.ref == 'refs/heads/main' &&
github.event.repository.fork == false
runs-on: ubuntu-latest
timeout-minutes: 2
environment: github-pages
Expand Down Expand Up @@ -71,6 +74,9 @@ jobs:
if-no-files-found: error

release:
if: |
github.ref == 'refs/heads/main' &&
github.event.repository.fork == false
runs-on: ubuntu-latest
timeout-minutes: 2
environment: github-pages
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/release-library.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ env:

jobs:
build:
if: |
github.ref == 'refs/heads/main' &&
github.event.repository.fork == false
runs-on: ubuntu-latest
timeout-minutes: 2
environment: FSI_DEP_NodeJs
Expand Down Expand Up @@ -62,6 +65,9 @@ jobs:
if-no-files-found: error

release:
if: |
github.ref == 'refs/heads/main' &&
github.event.repository.fork == false
needs: [ build ]
runs-on: ubuntu-latest
timeout-minutes: 2
Expand Down
10 changes: 6 additions & 4 deletions demo/src/app/cheat-sheet/remote/links.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ There are several ways to create links.

[I'm a reference-style link][Arbitrary case-insensitive reference text]

[I'm a relative reference to a repository file](favicon.ico)
[I'm a relative reference to a repository file](/localFile:favicon.ico)

[You can use numbers for reference-style link definitions][1]

Expand All @@ -24,11 +24,13 @@ Some text to show that the reference links can follow later.

[link text itself]: http://www.reddit.com

[I'm an Angular routerLink to another view with section](/routerLink:/syntax-highlight#language-pipe)
[Angular routerLink to another view with fragment](/routerLink:syntax-highlight#language-pipe)

[I'm an Angular routerLink to another view](/routerLink:/syntax-highlight)
[Angular routerLink to another view](/routerLink:syntax-highlight)

[I'm an Angular routerLink to a section on the same view](/routerLink:#headers)
[Angular routerLink with only fragment](#tables)

[I'm an Angular routerLink to current view with fragment](/routerLink:cheat-sheet#tables)

```html
<markdown src="/path/to/markdown.md"
Expand Down
2 changes: 1 addition & 1 deletion demo/src/app/playground/remote/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ Right aligned columns
[smart](https://google.com)
[Internal reference - Code Section](/routerLink:#code-section)
[Internal reference - Code Section](/routerLink:playground#code-section)
## Plugins Section
Expand Down
10 changes: 7 additions & 3 deletions demo/src/app/shared/anchor/anchor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,13 @@ export class AnchorService {
}

private isExternalUrl(url: string): boolean {
// Check if the URL starts with any of the following protocols: http, https, ftp, mailto, tel, file, data, www
const externalUrlPattern = /^(?!http(s?):\/\/|ftp(s?):\/\/|mailto:|tel:|file:\/\/|data:|www\.)[^#].*$/;
return externalUrlPattern.exec(url) == null;
// Check if the URL starts with any of the following protocols:
try {
const parsedUrl = new URL(url, window.location.origin);
return ['http:', 'https:', 'ftp:', 'ftps:', 'mailto:', 'tel:', 'sms:', 'geo:', 'file:', 'data:'].includes(parsedUrl.protocol);
} catch (e) {
return false;
}
}

private isRouterLink(element: HTMLAnchorElement): boolean {
Expand Down
4 changes: 2 additions & 2 deletions lib/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fsegurai/ngx-markdown",
"version": "18.1.0-beta.2",
"version": "18.1.0-beta.3",
"description": "Angular library that uses marked to parse markdown to html combined with Prism.js for syntax highlights",
"homepage": "https://github.com/fsegurai/ngx-markdown",
"license": "MIT",
Expand All @@ -27,7 +27,7 @@
"clipboard.js"
],
"dependencies": {
"tslib": "^2.8.0"
"tslib": "^2.8.1"
},
"peerDependencies": {
"@angular/common": "^18.0.0",
Expand Down
70 changes: 42 additions & 28 deletions lib/src/markdown-link.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ export class MarkdownLinkService {
*/
private isExternalUrl(href: string): boolean {
return !href
|| href.startsWith('/')
|| (href.startsWith('/') && !href.startsWith('/routerLink:'))
|| href.startsWith('http:')
|| href.startsWith('https:')
|| href.startsWith('www.')
|| href.startsWith('ftp:')
|| href.startsWith('ftps:')
|| href.startsWith('mailto:')
|| href.startsWith('tel:')
|| href.startsWith('sms:')
|| href.startsWith('geo:')
|| href.startsWith('ftp:')
|| href.startsWith('file:')
|| href.startsWith('data:');
|| href.startsWith('data:')
|| href.startsWith('/localFile:'); // Custom Angular flag for local files. e.g. /localFile:/path/to/file ~ /localFile:favicon.ico
}

/**
Expand All @@ -36,7 +39,10 @@ export class MarkdownLinkService {
* @private - This method is private and should not be accessed outside of this class
*/
private externalUrlHandler(target: HTMLElement): void {
const hyperlink = target.getAttribute('href')!;
let hyperlink = target.getAttribute('href')!;

// * Remove custom Angular flags from the URL for local files. e.g. /localFile:/path/to/file ~ /localFile:favicon.ico
hyperlink = hyperlink.replace('/localFile:', '');

target.setAttribute('target', '_blank');
window.open(hyperlink, '_blank');
Expand All @@ -49,9 +55,11 @@ export class MarkdownLinkService {
* @private - This method is private and should not be accessed outside of this class
*/
private isInternalUrl(href: string, element: HTMLAnchorElement): boolean {
const angularAnchorAttributes = ['_ngcontent', 'data-routerlink', 'routerlink'];

return !href || (
/^#|\/routerLink|\.\.\//.test(href) ||
element.getAttributeNames().some(n => n.includes('_ngcontent') || n.toLowerCase().includes('data-routerlink'))
element.getAttributeNames().some(n => angularAnchorAttributes.some(a => n.toLowerCase().includes(a)))
);
}

Expand All @@ -64,37 +72,45 @@ export class MarkdownLinkService {
private internalUrlHandler(target: HTMLAnchorElement, routerLinkOptions?: MarkdownRouterLinkOptions): void {
const anchor = target.nodeName.toLowerCase() === 'a' ? target : target.closest('a');
const path = anchor!.getAttribute('href')!;

if (routerLinkOptions?.internalBrowserHandler) {
if (path.startsWith('#')) {
this._router.navigate([], { fragment: path.slice(1) });
return;
}

// Get the routerLink commands to navigate to
let commands = [anchor!.getAttribute('data-routerLink')!];

/**
* Handle the navigation based on the options provided
* @param commands - string - Path to navigate to using the router service
* @param fragment - string - Fragment to scroll to after navigation
*/
const handleNavigation = (commands: string, fragment?: string) => {
let extras: NavigationExtras | undefined;
// Find the path in the routerLinkOptions

if (routerLinkOptions?.paths) {
extras = routerLinkOptions.paths[path];
extras = routerLinkOptions.paths[commands];
}
// Get the global options if no path was found
if (!extras && routerLinkOptions?.global) {
extras = routerLinkOptions.global;
}
// If the route has a fragment, add it to the extras and remove it from the commands to leave the path
if (path.includes('#')) {
if (fragment) {
extras = extras || {};
extras.fragment = path.split('#')[1];
commands[0] = commands[0].split('#')[0];
extras.fragment = fragment;
}

this._router.navigate([commands], extras);
};

if (routerLinkOptions?.internalBrowserHandler) {
if (path.startsWith('#')) {
this._router.navigate([], { fragment: path.slice(1) });
return;
}

// Remove the first slash from the path
commands = commands.map(c => c.startsWith('/') ? c.slice(1) : c);
if (path.startsWith('/routerLink:')) {
const routerLinkPath = path.replace('/routerLink:', '');
const [commands, fragment] = routerLinkPath.split('#');
handleNavigation(commands, fragment);
return;
}

// Navigate to the path using the router service
this._router.navigate(commands, extras);
// Fallback for other internal URLs
const [commands, fragment] = path.split('#');
handleNavigation(commands, fragment);
return;
} else {
try {
// Validate if there are more than one element with the same id
Expand All @@ -107,8 +123,6 @@ export class MarkdownLinkService {
console.error(error);
}
}

return;
}

/**
Expand Down
18 changes: 13 additions & 5 deletions lib/src/markdown.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import { PrismPlugin } from './prism-plugin';
export interface MarkdownRouterLinkOptions {
global?: NavigationExtras;
paths?: Record<string, NavigationExtras | undefined>;
internalBrowserHandler?: boolean;
internalDesktopHandler?: boolean;
externalBrowserHandler?: boolean;
internalBrowserHandler?: boolean; // Angular SPA navigation
internalDesktopHandler?: boolean; // Electron desktop navigation
externalBrowserHandler?: boolean; // External browser navigation
}

@Component({
Expand Down Expand Up @@ -174,8 +174,16 @@ export class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy {
map(() => this.element.nativeElement.querySelectorAll('a')),
switchMap(links => from(links)),
filter(link => link.getAttribute('href')?.includes('/routerLink:') === true),
tap(link => link.setAttribute('data-routerLink', link.getAttribute('href')!.replace('/routerLink:', ''))),
tap(link => link.setAttribute('href', link.getAttribute('href')!.replace('/routerLink:', ''))),
tap(link => {
const href = link.getAttribute('href')!;
const [path, fragment] = href.split('#');
link.setAttribute('data-routerLink', path);
link.setAttribute('href', `${path}${fragment ? `#${fragment}` : ''}`);
link.setAttribute('routerLink', `${path}${fragment ? `#${fragment}` : ''}`);
if (fragment) {
link.setAttribute('fragment', fragment);
}
}),
);

@HostListener('click', ['$event'])
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fsegurai/ngx-markdown",
"version": "18.1.0-beta.2",
"version": "18.1.0-beta.3",
"description": "Angular library that uses marked to parse markdown to html combined with Prism.js for syntax highlights",
"homepage": "https://github.com/fsegurai/ngx-markdown",
"license": "MIT",
Expand Down

0 comments on commit 474cbc9

Please sign in to comment.