61 lines
1.6 KiB
TypeScript
61 lines
1.6 KiB
TypeScript
import { Injectable, inject } from '@angular/core';
|
|
import { ElectronBridgeService } from './electron/electron-bridge.service';
|
|
|
|
/**
|
|
* Opens URLs in the system default browser (Electron) or a new tab (browser).
|
|
*
|
|
* Usage:
|
|
* inject(ExternalLinkService).open('https://example.com');
|
|
*/
|
|
@Injectable({ providedIn: 'root' })
|
|
export class ExternalLinkService {
|
|
private readonly electronBridge = inject(ElectronBridgeService);
|
|
|
|
/** Open a URL externally. Only http/https URLs are allowed. */
|
|
open(url: string): void {
|
|
if (!url || !(url.startsWith('http://') || url.startsWith('https://')))
|
|
return;
|
|
|
|
const electronApi = this.electronBridge.getApi();
|
|
|
|
if (electronApi) {
|
|
void electronApi.openExternal(url);
|
|
return;
|
|
}
|
|
|
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
}
|
|
|
|
/**
|
|
* Click handler for anchor elements. Call from a (click) binding or HostListener.
|
|
* Returns true if the click was handled (link opened externally), false otherwise.
|
|
*/
|
|
handleClick(evt: MouseEvent): boolean {
|
|
const target = (evt.target as HTMLElement)?.closest('a') as HTMLAnchorElement | null;
|
|
|
|
if (!target)
|
|
return false;
|
|
|
|
const href = target.href;
|
|
|
|
if (!href)
|
|
return false;
|
|
|
|
if (href.startsWith('javascript:') || href.startsWith('blob:') || href.startsWith('data:'))
|
|
return false;
|
|
|
|
const rawAttr = target.getAttribute('href');
|
|
|
|
if (rawAttr?.startsWith('#'))
|
|
return false;
|
|
|
|
if (target.hasAttribute('routerlink') || target.hasAttribute('ng-reflect-router-link'))
|
|
return false;
|
|
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
this.open(href);
|
|
return true;
|
|
}
|
|
}
|