handleTestCondition.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { customAlphabet } from 'nanoid/non-secure';
  2. import { visibleInViewport, isXPath } from '@/utils/helper';
  3. import FindElement from '@/utils/FindElement';
  4. import { automaRefDataStr } from './utils';
  5. const nanoid = customAlphabet('1234567890abcdef', 5);
  6. function handleConditionElement({ data, type }) {
  7. const selectorType = isXPath(data.selector) ? 'xpath' : 'cssSelector';
  8. const element = FindElement[selectorType](data);
  9. const { 1: actionType } = type.split('#');
  10. const elementActions = {
  11. exists: () => Boolean(element),
  12. notExists: () => !element,
  13. text: () => element?.innerText ?? null,
  14. visibleScreen: () => {
  15. if (!element) return false;
  16. return visibleInViewport(element);
  17. },
  18. visible: () => {
  19. if (!element) return false;
  20. const { visibility, display } = getComputedStyle(element);
  21. return visibility !== 'hidden' && display !== 'none';
  22. },
  23. invisible: () => {
  24. if (!element) return false;
  25. const { visibility, display } = getComputedStyle(element);
  26. const styleHidden = visibility === 'hidden' || display === 'none';
  27. return styleHidden || !visibleInViewport(element);
  28. },
  29. attribute: ({ attrName }) => {
  30. if (!element || !element.hasAttribute(attrName)) return null;
  31. return element.getAttribute(attrName);
  32. },
  33. };
  34. return elementActions[actionType](data);
  35. }
  36. function injectJsCode({ data, refData }) {
  37. return new Promise((resolve, reject) => {
  38. const varName = `automa${nanoid()}`;
  39. const scriptEl = document.createElement('script');
  40. scriptEl.textContent = `
  41. (async () => {
  42. const ${varName} = ${JSON.stringify(refData)};
  43. ${automaRefDataStr(varName)}
  44. try {
  45. ${data.code}
  46. } catch (error) {
  47. return {
  48. $isError: true,
  49. message: error.message,
  50. }
  51. }
  52. })()
  53. .then((detail) => {
  54. window.dispatchEvent(new CustomEvent('__automa-condition-code__', { detail }));
  55. });
  56. `;
  57. document.body.appendChild(scriptEl);
  58. const handleAutomaEvent = ({ detail }) => {
  59. scriptEl.remove();
  60. window.removeEventListener(
  61. '__automa-condition-code__',
  62. handleAutomaEvent
  63. );
  64. if (detail.$isError) {
  65. reject(new Error(detail.message));
  66. return;
  67. }
  68. resolve(detail);
  69. };
  70. window.addEventListener('__automa-condition-code__', handleAutomaEvent);
  71. });
  72. }
  73. export default async function (data) {
  74. let result = null;
  75. if (data.type.startsWith('element')) {
  76. result = await handleConditionElement(data);
  77. }
  78. if (data.type.startsWith('code')) {
  79. result = await injectJsCode(data);
  80. }
  81. return result;
  82. }