123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- import browser from 'webextension-polyfill';
- import { finder } from '@medv/finder';
- import { toCamelCase } from '@/utils/helper';
- import blocksHandler from './blocksHandler';
- import showExecutedBlock from './showExecutedBlock';
- import handleTestCondition from './handleTestCondition';
- import shortcutListener from './services/shortcutListener';
- // import elementObserver from './elementObserver';
- import { elementSelectorInstance } from './utils';
- const isMainFrame = window.self === window.top;
- function messageToFrame(frameElement, blockData) {
- return new Promise((resolve, reject) => {
- function onMessage({ data }) {
- if (data.type !== 'automa:block-execute-result') return;
- if (data.result?.$isError) {
- const error = new Error(data.result.message);
- error.data = data.result.data;
- reject(error);
- } else {
- resolve(data.result);
- }
- window.removeEventListener('message', onMessage);
- }
- window.addEventListener('message', onMessage);
- frameElement.contentWindow.postMessage(
- {
- type: 'automa:execute-block',
- blockData: { ...blockData, frameSelector: '' },
- },
- '*'
- );
- });
- }
- async function executeBlock(data) {
- const removeExecutedBlock = showExecutedBlock(data, data.executedBlockOnWeb);
- if (data.data?.selector?.includes('|>') && isMainFrame) {
- const [frameSelector, selector] = data.data.selector.split(/\|>(.+)/);
- const frameElement = document.querySelector(frameSelector);
- const frameError = (message) => {
- const error = new Error(message);
- error.data = { selector: frameSelector };
- return error;
- };
- if (!frameElement) throw frameError('iframe-not-found');
- const isFrameEelement = ['IFRAME', 'FRAME'].includes(frameElement.tagName);
- if (!isFrameEelement) throw frameError('not-iframe');
- data.data.selector = selector;
- data.data.$frameSelector = frameSelector;
- if (frameElement.contentDocument) {
- data.frameSelector = frameSelector;
- } else {
- const result = await messageToFrame(frameElement, data);
- return result;
- }
- }
- const handler = blocksHandler[toCamelCase(data.name)];
- if (handler) {
- const result = await handler(data);
- removeExecutedBlock();
- return result;
- }
- const error = new Error(`"${data.name}" doesn't have a handler`);
- console.error(error);
- throw error;
- }
- function messageListener({ data, source }) {
- if (data.type === 'automa:get-frame' && isMainFrame) {
- let frameRect = { x: 0, y: 0 };
- document.querySelectorAll('iframe').forEach((iframe) => {
- if (iframe.contentWindow !== source) return;
- frameRect = iframe.getBoundingClientRect();
- });
- source.postMessage(
- {
- frameRect,
- type: 'automa:the-frame-rect',
- },
- '*'
- );
- return;
- }
- if (data.type === 'automa:execute-block') {
- executeBlock(data.blockData)
- .then((result) => {
- window.top.postMessage(
- {
- result,
- type: 'automa:block-execute-result',
- },
- '*'
- );
- })
- .catch((error) => {
- console.error(error);
- window.top.postMessage(
- {
- result: {
- $isError: true,
- message: error.message,
- data: error.data || {},
- },
- type: 'automa:block-execute-result',
- },
- '*'
- );
- });
- }
- }
- (() => {
- if (window.isAutomaInjected) return;
- window.isAutomaInjected = true;
- window.addEventListener('message', messageListener);
- let contextElement = null;
- let $ctxTextSelection = '';
- if (isMainFrame) {
- shortcutListener();
- window.addEventListener('contextmenu', ({ target }) => {
- contextElement = target;
- $ctxTextSelection = window.getSelection().toString();
- });
- // window.addEventListener('load', elementObserver);
- }
- browser.runtime.onMessage.addListener((data) => {
- return new Promise((resolve, reject) => {
- if (data.isBlock) {
- executeBlock(data).then(resolve).catch(reject);
- } else {
- switch (data.type) {
- case 'condition-builder':
- handleTestCondition(data.data)
- .then((result) => resolve(result))
- .catch((error) => reject(error));
- break;
- case 'content-script-exists':
- resolve(true);
- break;
- case 'automa-element-selector': {
- const selectorInstance = elementSelectorInstance();
- resolve(selectorInstance);
- break;
- }
- case 'context-element': {
- let $ctxElSelector = '';
- if (contextElement) {
- $ctxElSelector = finder(contextElement);
- contextElement = null;
- }
- resolve({ $ctxElSelector, $ctxTextSelection });
- break;
- }
- default:
- resolve(null);
- }
- }
- });
- });
- })();
|