helper.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import browser from 'webextension-polyfill';
  2. export function scrollIfNeeded(element) {
  3. const { top, left, bottom, right } = element.getBoundingClientRect();
  4. const isInViewport =
  5. top >= 0 &&
  6. left >= 0 &&
  7. bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
  8. right <= (window.innerWidth || document.documentElement.clientWidth);
  9. if (!isInViewport) {
  10. element.scrollIntoView();
  11. }
  12. }
  13. export function sleep(timeout = 500) {
  14. return new Promise((resolve) => setTimeout(resolve, timeout));
  15. }
  16. export function findTriggerBlock(drawflow = {}) {
  17. if (!drawflow) return null;
  18. const blocks = Object.values(drawflow.drawflow?.Home?.data);
  19. if (!blocks) return null;
  20. return blocks.find(({ name }) => name === 'trigger');
  21. }
  22. export function throttle(callback, limit) {
  23. let waiting = false;
  24. return (...args) => {
  25. if (!waiting) {
  26. callback.apply(this, args);
  27. waiting = true;
  28. setTimeout(() => {
  29. waiting = false;
  30. }, limit);
  31. }
  32. };
  33. }
  34. export function convertArrObjTo2DArr(arr) {
  35. const keyIndex = new Map();
  36. const values = [[]];
  37. arr.forEach((obj) => {
  38. const keys = Object.keys(obj);
  39. const row = [];
  40. keys.forEach((key) => {
  41. if (!keyIndex.has(key)) {
  42. keyIndex.set(key, keyIndex.size);
  43. values[0].push(key);
  44. }
  45. const rowIndex = keyIndex.get(key);
  46. row[rowIndex] = obj[key];
  47. });
  48. values.push([...row]);
  49. });
  50. return values;
  51. }
  52. export function convert2DArrayToArrayObj(values) {
  53. let keyIndex = 0;
  54. const keys = values.shift();
  55. const result = [];
  56. for (let columnIndex = 0; columnIndex < values.length; columnIndex += 1) {
  57. const currentColumn = {};
  58. for (
  59. let rowIndex = 0;
  60. rowIndex < values[columnIndex].length;
  61. rowIndex += 1
  62. ) {
  63. let key = keys[rowIndex];
  64. if (!key) {
  65. keyIndex += 1;
  66. key = `_row${keyIndex}`;
  67. keys.push(key);
  68. }
  69. currentColumn[key] = values[columnIndex][rowIndex];
  70. }
  71. result.push(currentColumn);
  72. }
  73. return result;
  74. }
  75. export function parseJSON(data, def) {
  76. try {
  77. const result = JSON.parse(data);
  78. return result;
  79. } catch (error) {
  80. return def;
  81. }
  82. }
  83. export function parseFlow(flow) {
  84. const obj = typeof flow === 'string' ? parseJSON(flow, {}) : flow;
  85. return obj?.drawflow?.Home.data;
  86. }
  87. export function replaceMustache(str, replacer) {
  88. /* eslint-disable-next-line */
  89. return str.replace(/\{\{(.*?)\}\}/g, replacer);
  90. }
  91. export function openFilePicker(acceptedFileTypes = [], attrs = {}) {
  92. return new Promise((resolve) => {
  93. const input = document.createElement('input');
  94. input.type = 'file';
  95. input.accept = Array.isArray(acceptedFileTypes)
  96. ? acceptedFileTypes.join(',')
  97. : acceptedFileTypes;
  98. Object.entries(attrs).forEach(([key, value]) => {
  99. input[key] = value;
  100. });
  101. input.onchange = (event) => {
  102. const { files } = event.target;
  103. const validFiles = [];
  104. files.forEach((file) => {
  105. if (!acceptedFileTypes.includes(file.type)) return;
  106. validFiles.push(file);
  107. });
  108. resolve(validFiles);
  109. };
  110. input.click();
  111. });
  112. }
  113. export function fileSaver(filename, data) {
  114. const anchor = document.createElement('a');
  115. anchor.download = filename;
  116. anchor.href = data;
  117. anchor.dispatchEvent(new MouseEvent('click'));
  118. anchor.remove();
  119. }
  120. export function countDuration(started, ended) {
  121. const duration = Math.round((ended - started) / 1000);
  122. const minutes = parseInt((duration / 60) % 60, 10);
  123. const seconds = parseInt(duration % 60, 10);
  124. const getText = (num, suffix) => (num > 0 ? `${num}${suffix}` : '');
  125. return `${getText(minutes, 'm')} ${seconds}s`;
  126. }
  127. export function toCamelCase(str) {
  128. const result = str.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => {
  129. return index === 0 ? letter.toLowerCase() : letter.toUpperCase();
  130. });
  131. return result.replace(/\s+|[-]/g, '');
  132. }
  133. export function isObject(obj) {
  134. return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
  135. }
  136. export function objectHasKey(obj, key) {
  137. return Object.prototype.hasOwnProperty.call(obj, key);
  138. }
  139. export function isWhitespace(str) {
  140. return !/\S/.test(str);
  141. }
  142. export function debounce(callback, time = 200) {
  143. let interval;
  144. return (...args) => {
  145. clearTimeout(interval);
  146. return new Promise((resolve) => {
  147. interval = setTimeout(() => {
  148. interval = null;
  149. callback(...args);
  150. resolve();
  151. }, time);
  152. });
  153. };
  154. }
  155. export async function clearCache(workflow) {
  156. try {
  157. await browser.storage.local.remove(`state:${workflow.id}`);
  158. const flows = parseJSON(workflow.drawflow, null);
  159. const blocks = flows && flows.drawflow.Home.data;
  160. if (blocks) {
  161. Object.values(blocks).forEach(({ name, id }) => {
  162. if (name !== 'loop-data') return;
  163. localStorage.removeItem(`index:${id}`);
  164. });
  165. }
  166. return true;
  167. } catch (error) {
  168. console.error(error);
  169. return false;
  170. }
  171. }