Prechádzať zdrojové kódy

feat: enable edit selector in Automa element selector

Ahmad Kholid 3 rokov pred
rodič
commit
bd5faf83b8

+ 2 - 1
src/components/content/selector/SelectorQuery.vue

@@ -24,9 +24,9 @@
     <div class="mt-2 flex items-center">
       <ui-input
         :model-value="selector"
-        readonly
         placeholder="Element selector"
         class="leading-normal flex-1 h-full element-selector"
+        @change="$emit('selector', $event)"
       >
         <template #prepend>
           <button class="absolute ml-2 left-0" @click="copySelector">
@@ -76,6 +76,7 @@ defineEmits([
   'list',
   'parent',
   'child',
+  'selector',
   'update:selectorType',
   'update:selectList',
 ]);

+ 1 - 0
src/components/content/shared/SharedElementSelector.vue

@@ -58,6 +58,7 @@ const props = defineProps({
     default: () => [],
   },
   list: Boolean,
+  hide: Boolean,
   pause: Boolean,
   disabled: Boolean,
   onlyInList: Boolean,

+ 54 - 0
src/content/elementSelector/App.vue

@@ -50,6 +50,7 @@
           v-model:selectList="state.selectList"
           :selector="state.elSelector"
           :selected-count="state.selectedElements.length"
+          @selector="updateSelector"
           @parent="selectElementPath('up')"
           @child="selectElementPath('down')"
         />
@@ -79,7 +80,9 @@
 </template>
 <script setup>
 import { reactive, ref, watch, inject, onMounted, onBeforeUnmount } from 'vue';
+import { debounce } from '@/utils/helper';
 import { finder } from '@medv/finder';
+import FindElement from '@/utils/FindElement';
 import SelectorQuery from '@/components/content/selector/SelectorQuery.vue';
 import SharedElementSelector from '@/components/content/shared/SharedElementSelector.vue';
 import SelectorElementsDetail from '@/components/content/selector/SelectorElementsDetail.vue';
@@ -120,6 +123,50 @@ const cardElementObserver = new ResizeObserver(([entry]) => {
   cardRect.height = height;
 });
 
+const updateSelector = debounce((selector) => {
+  let frameSelector;
+  let elSelector = selector;
+
+  if (selector.includes('|>')) {
+    [frameSelector, elSelector] = selector.split(/\|>(.+)/);
+  }
+
+  const selectorType = state.selectorType === 'css' ? 'cssSelector' : 'xpath';
+
+  try {
+    if (frameSelector) {
+      const frame = FindElement[selectorType]({
+        selector: frameSelector,
+        multiple: false,
+      });
+      if (!['IFRAME', 'FRAME'].includes(frame.tagName)) return;
+
+      const { top, left } = frame.getBoundingClientRect();
+      frame.contentWindow.postMessage(
+        {
+          selectorType,
+          selector: elSelector,
+          type: 'automa:find-element',
+          frameRect: { top, left },
+        },
+        '*'
+      );
+      return;
+    }
+
+    const elements = FindElement[selectorType]({
+      selector: elSelector,
+      multiple: true,
+    });
+    state.selectedElements = Array.from(elements || []).map((el) =>
+      getElementRect(el, true)
+    );
+  } catch (error) {
+    console.error(error);
+    state.selectedElements = [];
+  }
+}, 200);
+
 function toggleHighlightElement({ index, highlight }) {
   state.selectedElements[index].highlight = highlight;
 }
@@ -180,6 +227,11 @@ function selectElementPath(type) {
 function onMouseup() {
   if (state.isDragging) state.isDragging = false;
 }
+function onMessage({ data }) {
+  if (data.type !== 'automa:selected-elements') return;
+
+  state.selectedElements = data.elements;
+}
 function destroy() {
   rootElement.style.display = 'none';
 
@@ -203,12 +255,14 @@ function destroy() {
 function attachListeners() {
   cardElementObserver.observe(cardEl.value);
 
+  window.addEventListener('message', onMessage);
   window.addEventListener('mouseup', onMouseup);
   window.addEventListener('mousemove', onMousemove);
 }
 function detachListeners() {
   cardElementObserver.disconnect();
 
+  window.removeEventListener('message', onMessage);
   window.removeEventListener('mouseup', onMouseup);
   window.removeEventListener('mousemove', onMousemove);
 }

+ 36 - 3
src/content/elementSelector/selectorFrameContext.js

@@ -1,3 +1,4 @@
+import FindElement from '@/utils/FindElement';
 import { getElementRect } from '../utils';
 import findElementList from './listSelector';
 import generateElementsSelector from './generateElementsSelector';
@@ -76,10 +77,42 @@ function resetElementSelector(data) {
     prevSelectedElement = null;
   }
 }
+function findElement({ selector, selectorType, frameRect }) {
+  const payload = {
+    elements: [],
+    type: 'automa:selected-elements',
+  };
+
+  try {
+    const elements = FindElement[selectorType]({ multiple: true, selector });
+
+    payload.elements = Array.from(elements || []).map((el) =>
+      getElementRectWithOffset(el, {
+        withAttributes: true,
+        click: true,
+        ...frameRect,
+      })
+    );
+  } catch (error) {
+    console.error(error);
+    payload.elements = [];
+  }
+
+  window.top.postMessage(payload, '*');
+}
 function onMessage({ data }) {
-  if (data.type === 'automa:get-element-rect') getElementsRect(data);
-  else if (data.type === 'automa:reset-element-selector')
-    resetElementSelector(data);
+  switch (data.type) {
+    case 'automa:get-element-rect':
+      getElementsRect(data);
+      break;
+    case 'automa:reset-element-selector':
+      resetElementSelector(data);
+      break;
+    case 'automa:find-element':
+      findElement(data);
+      break;
+    default:
+  }
 }
 
 export default function () {