Browse Source

feat: add xpath selector

Ahmad Kholid 3 years ago
parent
commit
12c415914d

+ 1 - 0
src/background/workflow-engine/blocks-handler/handler-loop-breakpoint.js

@@ -20,6 +20,7 @@ function loopBreakpoint(block, prevBlockData) {
       });
     } else {
       delete this.loopList[block.data.loopId];
+      delete this.loopData[block.data.loopId];
 
       resolve({
         data: prevBlockData,

+ 22 - 1
src/components/newtab/workflow/edit/EditInteractionBase.vue

@@ -9,6 +9,16 @@
         class="w-full mb-2"
         @change="updateData({ description: $event })"
       />
+      <ui-select
+        :model-value="data.findBy || 'cssSelector'"
+        :placeholder="t('workflow.blocks.base.findElement.placeholder')"
+        class="w-full mb-2"
+        @change="updateData({ findBy: $event })"
+      >
+        <option v-for="type in selectorTypes" :key="type" :value="type">
+          {{ t(`workflow.blocks.base.findElement.options.${type}`) }}
+        </option>
+      </ui-select>
       <ui-input
         v-if="!hideSelector"
         :model-value="data.selector"
@@ -16,7 +26,9 @@
         class="mb-1 w-full"
         @change="updateData({ selector: $event })"
       />
-      <template v-if="!hideSelector">
+      <template
+        v-if="!hideSelector && (data.findBy || 'cssSelector') === 'cssSelector'"
+      >
         <ui-checkbox
           v-if="!data.disableMultiple && !hideMultiple"
           :title="t('workflow.blocks.base.multiple.title')"
@@ -39,6 +51,7 @@
   </div>
 </template>
 <script setup>
+import { onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 
 const props = defineProps({
@@ -63,10 +76,18 @@ const emit = defineEmits(['update:data', 'change']);
 
 const { t } = useI18n();
 
+const selectorTypes = ['cssSelector', 'xpath'];
+
 function updateData(value) {
   const payload = { ...props.data, ...value };
 
   emit('update:data', payload);
   emit('change', payload);
 }
+
+onMounted(() => {
+  if (!props.data.findBy) {
+    updateData({ findBy: 'cssSelector' });
+  }
+});
 </script>

+ 2 - 2
src/content/element-selector/App.vue

@@ -14,11 +14,12 @@
       text-gray-900
       left-0
     "
-    style="z-index: 9999999999; font-family: Inter, sans-serif"
+    style="z-index: 9999999999; font-family: Inter, sans-serif; font-size: 16px"
   >
     <div
       ref="cardEl"
       :style="{ transform: `translate(${cardRect.x}px, ${cardRect.y}px)` }"
+      style="width: 320px"
       class="
         absolute
         root-card
@@ -28,7 +29,6 @@
         p-4
         pointer-events-auto
         rounded-lg
-        w-80
       "
     >
       <div

+ 1 - 0
src/content/element-selector/index.js

@@ -4,6 +4,7 @@ async function getStyles() {
     const mainCSS = await response.text();
 
     const fontCSS = `
+      :host { font-size: 16px }
       @font-face {
         font-family: Inter var;
         font-weight: 100 900;

+ 5 - 9
src/content/helper.js

@@ -1,3 +1,5 @@
+import FindElement from '@/utils/find-element';
+
 /* eslint-disable consistent-return */
 
 export function markElement(el, { id, data }) {
@@ -10,18 +12,12 @@ export function handleElement({ data, id }, callback, errCallback) {
   if (!data || !data.selector) return null;
 
   try {
-    const blockIdAttr = `block--${id}`;
-    const selector = data.markEl
-      ? `${data.selector.trim()}:not([${blockIdAttr}])`
-      : data.selector;
-
-    const element = data.multiple
-      ? document.querySelectorAll(selector)
-      : document.querySelector(selector);
+    data.blockIdAttr = `block--${id}`;
+    const element = FindElement[data.findBy || 'cssSelector'](data);
 
     if (typeof callback === 'boolean' && callback) return element;
 
-    if (data.multiple) {
+    if (data.multiple && (data.findBy || 'cssSelector') === 'cssSelector') {
       element.forEach((el) => {
         markElement(el, { id, data });
         callback(el);

+ 7 - 0
src/locales/en/blocks.json

@@ -11,6 +11,13 @@
     "blocks": {
       "base": {
         "selector": "Element selector",
+        "findElement": {
+          "placeholder": "Find element by",
+          "options": {
+            "cssSelector": "CSS Selector",
+            "xpath": "XPath"
+          }
+        },
         "markElement": {
           "title": "An element will not be selected if have been selected before",
           "text": "Mark element"

+ 23 - 0
src/utils/find-element.js

@@ -0,0 +1,23 @@
+class FindElement {
+  static cssSelector(data) {
+    const selector = data.markEl
+      ? `${data.selector.trim()}:not([${data.blockIdAttr}])`
+      : data.selector;
+
+    return data.multiple
+      ? document.querySelectorAll(selector)
+      : document.querySelector(selector);
+  }
+
+  static xpath(data) {
+    return document.evaluate(
+      data.selector,
+      document,
+      null,
+      XPathResult.FIRST_ORDERED_NODE_TYPE,
+      null
+    ).singleNodeValue;
+  }
+}
+
+export default FindElement;

+ 10 - 1
src/utils/shared.js

@@ -182,6 +182,7 @@ export const tasks = {
     maxConnection: 1,
     data: {
       description: '',
+      findBy: 'cssSelector',
       selector: '',
       markEl: false,
       multiple: false,
@@ -215,6 +216,7 @@ export const tasks = {
     maxConnection: 1,
     data: {
       description: '',
+      findBy: 'cssSelector',
       selector: '',
       markEl: false,
       multiple: false,
@@ -253,6 +255,7 @@ export const tasks = {
     maxConnection: 1,
     data: {
       description: '',
+      findBy: 'cssSelector',
       selector: 'html',
       markEl: false,
       multiple: false,
@@ -277,6 +280,7 @@ export const tasks = {
     maxConnection: 1,
     data: {
       description: '',
+      findBy: 'cssSelector',
       selector: '',
       markEl: false,
       disableMultiple: true,
@@ -295,6 +299,7 @@ export const tasks = {
     maxConnection: 1,
     data: {
       description: '',
+      findBy: 'cssSelector',
       selector: '',
       markEl: false,
       multiple: false,
@@ -316,12 +321,13 @@ export const tasks = {
     maxConnection: 1,
     data: {
       description: '',
+      findBy: 'cssSelector',
       selector: '',
       markEl: false,
       multiple: false,
       selected: true,
       clearValue: true,
-      getValue: true,
+      getValue: false,
       saveData: true,
       dataColumn: '',
       type: 'text-field',
@@ -388,6 +394,7 @@ export const tasks = {
     maxConnection: 1,
     data: {
       description: '',
+      findBy: 'cssSelector',
       selector: '',
       markEl: false,
       multiple: false,
@@ -422,6 +429,7 @@ export const tasks = {
     allowedInputs: true,
     maxConnection: 1,
     data: {
+      findBy: 'cssSelector',
       selector: '',
       tryCount: 1,
       timeout: 500,
@@ -497,6 +505,7 @@ export const tasks = {
     allowedInputs: true,
     maxConnection: 1,
     data: {
+      findBy: 'cssSelector',
       selector: '',
       windowType: 'main-window',
     },