0 directories, 7 files

util

Home / testing / ai / tinai / util
/**
 * Asynchronous, clipboard, and timer utilities for TinAI.
 */

/**
 * Creates a debounced function that delays invoking func until after wait milliseconds.
 * Provides a .cancel() method to abort any scheduled execution.
 * @param {Function} func - Function to debounce.
 * @param {number} [wait=250] - Milliseconds to delay.
 * @returns {Function & { cancel: Function }} Debounced wrapper function with cancel method.
 */
export function debounce(func, wait = 250) {
	let timeout = null;
	const executedFunction = function(...args) {
		const later = () => {
			timeout = null;
			func.apply(this, args);
		};
		if (timeout) {
			clearTimeout(timeout);
			timeout = null;
		}
		timeout = setTimeout(later, wait);
	};
	executedFunction.cancel = function() {
		if (timeout) {
			clearTimeout(timeout);
			timeout = null;
		}
	};
	return executedFunction;
}

/**
 * Copies plain text to the clipboard with modern clipboard API and fallback.
 * @param {string} text - String to copy.
 * @param {HTMLElement|null} [feedbackButton=null] - Optional button to show visual feedback on.
 * @returns {Promise<boolean>} Whether copy succeeded.
 */
export async function copyToClipboard(text, feedbackButton = null) {
	const applyFeedback = () => {
		if (!feedbackButton) return;
		const originalText = feedbackButton.textContent;
		feedbackButton.textContent = 'Copied!';
		feedbackButton.disabled = true;
		setTimeout(() => {
			feedbackButton.textContent = originalText;
			feedbackButton.disabled = false;
		}, 1500);
	};

	if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
		try {
			await navigator.clipboard.writeText(text || '');
			applyFeedback();
			return true;
		} catch (err) {
			console.warn('navigator.clipboard.writeText failed, falling back to legacy execCommand:', err);
		}
	}

	try {
		const textarea = document.createElement('textarea');
		textarea.value = text || '';
		textarea.setAttribute('readonly', '');
		textarea.style.position = 'fixed';
		textarea.style.left = '-9999px';
		textarea.style.top = '0';
		document.body.appendChild(textarea);
		textarea.select();
		const successful = document['execCommand']('copy');
		document.body.removeChild(textarea);
		if (successful) {
			applyFeedback();
		}
		return !!successful;
	} catch (err) {
		console.error('All clipboard copy methods failed:', err);
		return false;
	}
}
🌐
async-utils.js ×
Type: Web, text/plain
2.32 Kilobytes
Last Modified 2026-09-04 18:10:48
⬇ Download File