Skip to content

Commit b1a3a2d

Browse files
committed
Merged in DSC-1484-create-utility-functions-to-handle-internal-and-external-links (pull request DSpace#1272)
DSC-1484 create utility functions to handle internal and external links Approved-by: Davide Negretti
2 parents 567fdf8 + d520830 commit b1a3a2d

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { TestBed, waitForAsync } from '@angular/core/testing';
2+
import { InternalLinkService } from './internal-link.service';
3+
import { NativeWindowService } from './window.service';
4+
5+
describe('InternalLinkService', () => {
6+
let service: InternalLinkService;
7+
8+
beforeEach(waitForAsync(() => {
9+
return TestBed.configureTestingModule({
10+
providers: [
11+
InternalLinkService,
12+
{ provide: NativeWindowService, useValue: { nativeWindow: { location: { origin: 'https://currentdomain' } } } },
13+
],
14+
}).compileComponents();
15+
}));
16+
17+
beforeEach(() => {
18+
service = TestBed.inject(InternalLinkService);
19+
});
20+
21+
describe('isLinkInternal', () => {
22+
it('should return true for internal link starting with "/"', () => {
23+
const result = service.isLinkInternal('/my-link');
24+
expect(result).toBe(true);
25+
});
26+
27+
it('should return true for internal link starting with currentURL', () => {
28+
const result = service.isLinkInternal('https://currentdomain/my-link');
29+
expect(result).toBe(true);
30+
});
31+
32+
it('should return true for internal link starting with "currentdomain"', () => {
33+
const result = service.isLinkInternal('currentdomain/my-link');
34+
expect(result).toBe(true);
35+
});
36+
37+
it('should return false for external link', () => {
38+
const result = service.isLinkInternal('https://externaldomain/my-link');
39+
expect(result).toBe(false);
40+
});
41+
42+
it('should return true for internal link without leading "/"', () => {
43+
const result = service.isLinkInternal('my-link');
44+
expect(result).toBe(true);
45+
});
46+
});
47+
48+
describe('transformInternalLink', () => {
49+
it('should transform internal link by removing currentURL', () => {
50+
const result = service.getRelativePath('https://currentdomain/my-link');
51+
expect(result).toBe('/my-link');
52+
});
53+
54+
it('should transform internal link by adding leading "/" if missing', () => {
55+
const result = service.getRelativePath('currentdomain/my-link');
56+
expect(result).toBe('/my-link');
57+
});
58+
59+
it('should return unchanged link for external link', () => {
60+
const result = service.getRelativePath('https://externalDomain/my-link');
61+
expect(result).toBe('https://externalDomain/my-link');
62+
});
63+
64+
it('should return unchanged link for internal link with leading "/"', () => {
65+
const result = service.getRelativePath('/my-link');
66+
expect(result).toBe('/my-link');
67+
});
68+
});
69+
70+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Inject, Injectable } from '@angular/core';
2+
import { NativeWindowRef, NativeWindowService } from './window.service';
3+
4+
/**
5+
* LinkService provides utility functions for working with links, such as checking if a link is internal
6+
* and transforming internal links based on the current URL.
7+
*/
8+
@Injectable()
9+
export class InternalLinkService {
10+
currentURL = this._window.nativeWindow.location.origin;
11+
12+
constructor(
13+
@Inject(NativeWindowService) protected _window: NativeWindowRef,
14+
) {
15+
16+
}
17+
18+
/**
19+
* Check if the provided link is internal, i.e., it starts with a '/' or matches the current URL.
20+
*
21+
* @param link The link to be checked.
22+
* @returns A boolean indicating whether the link is internal.
23+
*/
24+
public isLinkInternal(link: string): boolean {
25+
// Create a Domain object for the provided link
26+
const currentDomain = new URL(this.currentURL).hostname;
27+
28+
return link.startsWith('/')
29+
|| link.startsWith(this.currentURL)
30+
|| link.startsWith(currentDomain)
31+
|| link === currentDomain
32+
|| !link.includes('://');
33+
}
34+
35+
/**
36+
* Get the relative path for an internal link based on the current URL.
37+
*
38+
* @param link The internal link to be transformed.
39+
* @returns The relative path for the given internal link.
40+
*/
41+
public getRelativePath(link: string): string {
42+
// Create a Domain object for the provided link
43+
const currentDomain = new URL(this.currentURL).hostname;
44+
45+
if (link.startsWith(this.currentURL)) {
46+
const currentSegments = link.substring(this.currentURL.length);
47+
return currentSegments.startsWith('/') ? currentSegments : `/${currentSegments}`;
48+
}
49+
50+
if (link.startsWith(currentDomain)) {
51+
const currentSegments = link.substring(currentDomain.length);
52+
return currentSegments.startsWith('/') ? currentSegments : `/${currentSegments}`;
53+
}
54+
55+
return link;
56+
}
57+
}

0 commit comments

Comments
 (0)