All files / lib inappbrowser.ts

91.17% Statements 31/34
90% Branches 9/10
90.9% Functions 10/11
91.17% Lines 31/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                              4x 4x 1x     3x 1x   2x 2x   2x 2x                     5x 1x     4x   4x 3x 2x 2x       4x               4x 4x       5x 5x         5x 5x             1x 1x             1x 1x   1x       1x         1x         1x      
import type { OpenWebViewOptions } from '@capgo/inappbrowser';
 
import { InAppBrowser } from '@capgo/inappbrowser';
 
type OpenInAppBrowserOptions = {
	title?: string;
	onUrlChange?: (browser: InAppBrowserInstance, url: string) => Promise<void> | void;
};
 
/**
 * Attachment that gets the URL to open from the href attribute. Must be set on <a> elements.
 * Also uses the title attribute as the title for the in-app browser, unless explicitly specified.
 * Only on mobile native platforms, it opens a in-app browser instead of navigating. On other platforms, it does nothing.
 */
export function inAppBrowser(options?: OpenInAppBrowserOptions): Attachment {
	return (node: HTMLElement) => {
		if (!Capacitor.isNativePlatform()) {
			return;
		}
 
		if (!(node instanceof HTMLAnchorElement)) {
			throw new Error('inAppBrowser attachment can only be used on <a> elements');
		}
		node.onclick = (event) => {
			event.preventDefault();
 
			const url = node.href;
			void openInAppBrowser(url, {
				title: node.title,
				...options,
			}).catch((error) => {
				console.error('Failed to open in-app browser:', error);
			});
		};
	};
}
 
export async function openInAppBrowser(url: string | URL, options?: OpenInAppBrowserOptions) {
	if (!Capacitor.isNativePlatform()) {
		throw new Error('In-app browser is only supported on native platforms');
	}
 
	const instance = new InAppBrowserInstance();
 
	await InAppBrowser.addListener('urlChangeEvent', async (event) => {
		if (event.id === instance.id) {
			instance.currentUrl = event.url;
			await options.onUrlChange?.(instance, event.url);
		}
	});
 
	await instance.open(url, { title: options?.title });
}
 
class InAppBrowserInstance {
	currentUrl: string | undefined;
	id: string | undefined;
 
	constructor() {
		this.currentUrl = undefined;
		this.id = undefined;
	}
 
	async open(url: string | URL, options?: Omit<OpenWebViewOptions, 'url'>) {
		try {
			const webview = await InAppBrowser.openWebView({
				url,
				...options,
			});
 
			this.id = webview.id;
			this.currentUrl = url;
		} catch (error) {
			console.error('Failed to open URL in in-app browser', error);
		}
	}
 
	async clearCookies() {
		try {
			await InAppBrowser.clearCookies({ url: this.currentUrl });
		} catch (error) {
			console.error('Failed to clear cookies for in-app browser', error);
		}
	}
 
	async close() {
		try {
			await InAppBrowser.close({ id: this.id });
		} catch (err) {
			console.error(
				'Failed to close in-app browser, it might have already been closed. Calling .hide',
				err
			);
			await InAppBrowser.hide({ url: this.currentUrl });
		}
	}
 
	async cookie(key: string) {
		const cookies = await InAppBrowser.getCookies({
			url: this.currentUrl,
			includeHttpOnly: true,
		});
 
		return cookies[key] ?? null;
	}
}