import browser from 'webextension-polyfill'; export async function getActiveTab() { try { const tabsQuery = { active: true, url: '*://*/*', }; const window = await browser.windows.getLastFocused({ populate: true, windowTypes: ['normal'], }); const windowId = window.id; if (windowId) tabsQuery.windowId = windowId; else tabsQuery.lastFocusedWindow = true; const [tab] = await browser.tabs.query(tabsQuery); return tab; } catch (error) { console.error(error); return null; } } export function isXPath(str) { const regex = /^([(/@]|id\()/; return regex.test(str); } export function visibleInViewport(element) { const { top, left, bottom, right, height, width } = element.getBoundingClientRect(); if (height === 0 || width === 0) return false; return ( top >= 0 && left >= 0 && bottom <= (window.innerHeight || document.documentElement.clientHeight) && right <= (window.innerWidth || document.documentElement.clientWidth) ); } export function sleep(timeout = 500) { return new Promise((resolve) => { setTimeout(() => { resolve(); }, timeout); }); } export function findTriggerBlock(drawflow = {}) { if (!drawflow) return null; if (drawflow.drawflow) { const blocks = Object.values(drawflow.drawflow?.Home?.data ?? {}); if (!blocks) return null; return blocks.find(({ name }) => name === 'trigger'); } if (drawflow.nodes) { return drawflow.nodes.find((node) => node.label === 'trigger'); } return null; } export function throttle(callback, limit) { let waiting = false; return (...args) => { if (!waiting) { callback.apply(this, args); waiting = true; setTimeout(() => { waiting = false; }, limit); } }; } export function convertArrObjTo2DArr(arr) { const keyIndex = new Map(); const values = [[]]; arr.forEach((obj) => { const keys = Object.keys(obj); const row = []; keys.forEach((key) => { if (!keyIndex.has(key)) { keyIndex.set(key, keyIndex.size); values[0].push(key); } const value = obj[key]; const rowIndex = keyIndex.get(key); row[rowIndex] = typeof value === 'object' ? JSON.stringify(value) : value; }); values.push([...row]); }); return values; } export function convert2DArrayToArrayObj(values) { let keyIndex = 0; const keys = values.shift(); const result = []; for (let columnIndex = 0; columnIndex < values.length; columnIndex += 1) { const currentColumn = {}; for ( let rowIndex = 0; rowIndex < values[columnIndex].length; rowIndex += 1 ) { let key = keys[rowIndex]; if (!key) { keyIndex += 1; key = `_row${keyIndex}`; keys.push(key); } currentColumn[key] = values[columnIndex][rowIndex]; } result.push(currentColumn); } return result; } export function parseJSON(data, def) { try { const result = JSON.parse(data); return result; } catch (error) { return def; } } export function parseFlow(flow) { const obj = typeof flow === 'string' ? parseJSON(flow, {}) : flow; return obj; } export function replaceMustache(str, replacer) { /* eslint-disable-next-line */ return str.replace(/\{\{(.*?)\}\}/g, replacer); } export function openFilePicker(acceptedFileTypes = [], attrs = {}) { return new Promise((resolve) => { const input = document.createElement('input'); input.type = 'file'; input.accept = Array.isArray(acceptedFileTypes) ? acceptedFileTypes.join(',') : acceptedFileTypes; Object.entries(attrs).forEach(([key, value]) => { input[key] = value; }); input.onchange = (event) => { const { files } = event.target; const validFiles = []; Array.from(files).forEach((file) => { if (!acceptedFileTypes.includes(file.type)) return; validFiles.push(file); }); resolve(validFiles); }; input.click(); }); } export function fileSaver(filename, data) { const anchor = document.createElement('a'); anchor.download = filename; anchor.href = data; anchor.dispatchEvent(new MouseEvent('click')); anchor.remove(); } export function countDuration(started, ended) { const duration = Math.round((ended - started) / 1000); const minutes = Math.floor(duration / 60); const seconds = Math.floor(duration % 60); const getText = (num, suffix) => (num > 0 ? `${num}${suffix}` : ''); return `${getText(minutes, 'm')} ${seconds}s`; } export function toCamelCase(str, capitalize = false) { const result = str.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => { return index === 0 && !capitalize ? letter.toLowerCase() : letter.toUpperCase(); }); return result.replace(/\s+|[-]/g, ''); } export function isObject(obj) { return typeof obj === 'object' && obj !== null && !Array.isArray(obj); } export function objectHasKey(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } export function isWhitespace(str) { return !/\S/.test(str); } export function debounce(callback, time = 200) { let interval; return (...args) => { clearTimeout(interval); return new Promise((resolve) => { interval = setTimeout(() => { interval = null; callback(...args); resolve(); }, time); }); }; } export async function clearCache(workflow) { try { await browser.storage.local.remove(`state:${workflow.id}`); const flows = parseJSON(workflow.drawflow, null); const blocks = flows && flows.drawflow.Home.data; if (blocks) { Object.values(blocks).forEach(({ name, id }) => { if (name !== 'loop-data') return; localStorage.removeItem(`index:${id}`); }); } return true; } catch (error) { console.error(error); return false; } } export function arraySorter({ data, key, order = 'asc' }) { let runCounts = {}; const copyData = data.slice(); if (key === 'mostUsed') { runCounts = parseJSON(localStorage.getItem('runCounts'), {}) || {}; } return copyData.sort((a, b) => { let comparison = 0; let itemA = a[key] || a; let itemB = b[key] || b; if (key === 'mostUsed') { itemA = runCounts[a.id] || 0; itemB = runCounts[b.id] || 0; } if (itemA > itemB) { comparison = 1; } else if (itemA < itemB) { comparison = -1; } return order === 'desc' ? comparison * -1 : comparison; }); }