浏览代码

feat: add select and verify element

Ahmad Kholid 2 年之前
父节点
当前提交
6f0badf16e

+ 5 - 0
src/components/newtab/shared/SharedConditionBuilder/ConditionBuilderInputs.vue

@@ -50,6 +50,10 @@
             class="w-full"
           />
         </edit-autocomplete>
+        <SharedElSelectorActions
+          v-if="name === 'selector'"
+          v-model:selector="inputsData[index].data[name]"
+        />
       </template>
     </div>
     <ui-select
@@ -81,6 +85,7 @@ import {
   completeFromGlobalScope,
 } from '@/utils/codeEditorAutocomplete';
 import { conditionBuilder } from '@/utils/shared';
+import SharedElSelectorActions from '@/components/newtab/shared/SharedElSelectorActions.vue';
 import EditAutocomplete from '../../workflow/edit/EditAutocomplete.vue';
 
 const SharedCodemirror = defineAsyncComponent(() =>

+ 63 - 0
src/components/newtab/shared/SharedElSelectorActions.vue

@@ -0,0 +1,63 @@
+<template>
+  <div class="inline-flex items-center">
+    <ui-button
+      v-tooltip.group="$t('workflow.blocks.base.element.select')"
+      icon
+      class="mr-2"
+      @click="selectElement"
+    >
+      <v-remixicon name="riFocus3Line" />
+    </ui-button>
+    <ui-button
+      v-tooltip.group="$t('workflow.blocks.base.element.verify')"
+      :disabled="!selector"
+      icon
+      @click="verifySelector"
+    >
+      <v-remixicon name="riCheckDoubleLine" />
+    </ui-button>
+  </div>
+</template>
+<script setup>
+import { useToast } from 'vue-toastification';
+import { useGroupTooltip } from '@/composable/groupTooltip';
+import elementSelector from '@/newtab/utils/elementSelector';
+
+const props = defineProps({
+  findBy: {
+    type: String,
+    default: null,
+  },
+  multiple: {
+    type: Boolean,
+    default: false,
+  },
+  selector: {
+    type: String,
+    default: '',
+  },
+});
+const emit = defineEmits(['update:selector']);
+
+useGroupTooltip();
+const toast = useToast();
+
+function selectElement() {
+  elementSelector.selectElement().then((selector) => {
+    emit('update:selector', selector);
+  });
+}
+function verifySelector() {
+  elementSelector
+    .verifySelector({
+      selector: props.selector,
+      multiple: props.multiple,
+      findBy: props.findBy,
+    })
+    .then((result) => {
+      if (!result.notFound) return;
+
+      toast.error('Element not found');
+    });
+}
+</script>

+ 7 - 34
src/components/newtab/workflow/edit/EditInteractionBase.vue

@@ -21,22 +21,12 @@
             {{ t(`workflow.blocks.base.findElement.options.${type}`) }}
           </option>
         </ui-select>
-        <ui-button
-          v-tooltip.group="t('workflow.blocks.base.element.select')"
-          icon
-          class="mr-2"
-          @click="selectElement"
-        >
-          <v-remixicon name="riFocus3Line" />
-        </ui-button>
-        <ui-button
-          v-tooltip.group="t('workflow.blocks.base.element.verify')"
-          :disabled="!data.selector"
-          icon
-          @click="verifySelector"
-        >
-          <v-remixicon name="riCheckDoubleLine" />
-        </ui-button>
+        <SharedElSelectorActions
+          :find-by="data.findBy"
+          :selector="data.selector"
+          :multiple="data.multiple"
+          @update:selector="updateData({ selector: $event })"
+        />
       </div>
       <edit-autocomplete v-if="!hideSelector" class="mb-1">
         <ui-input
@@ -105,8 +95,7 @@
 <script setup>
 import { onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { useToast } from 'vue-toastification';
-import elementSelector from '@/newtab/utils/elementSelector';
+import SharedElSelectorActions from '@/components/newtab/shared/SharedElSelectorActions.vue';
 import EditAutocomplete from './EditAutocomplete.vue';
 
 const props = defineProps({
@@ -135,7 +124,6 @@ const props = defineProps({
 const emit = defineEmits(['update:data', 'change']);
 
 const { t } = useI18n();
-const toast = useToast();
 
 const selectorTypes = ['cssSelector', 'xpath'];
 
@@ -145,21 +133,6 @@ function updateData(value) {
   emit('update:data', payload);
   emit('change', payload);
 }
-function selectElement() {
-  elementSelector.selectElement().then((selector) => {
-    updateData({ selector });
-  });
-}
-function verifySelector() {
-  const { selector, multiple, findBy } = props.data;
-  elementSelector
-    .verifySelector({ selector, multiple, findBy })
-    .then((result) => {
-      if (!result.notFound) return;
-
-      toast.error('Element not found');
-    });
-}
 
 onMounted(() => {
   if (!props.data.findBy) {

+ 8 - 2
src/components/newtab/workflow/edit/EditLoopData.vue

@@ -40,15 +40,20 @@
       @change="updateData({ variableName: $event })"
     />
     <template v-else-if="data.loopThrough === 'elements'">
-      <edit-autocomplete class="mt-2">
+      <edit-autocomplete class="mt-2" trigger-class="!flex items-end">
         <ui-input
           :model-value="data.elementSelector"
           :label="t('workflow.blocks.base.selector')"
           autocomplete="off"
           placeholder="CSS Selector or XPath"
-          class="w-full"
+          class="flex-1 mr-2"
           @change="updateData({ elementSelector: $event })"
         />
+        <shared-el-selector-actions
+          :multiple="true"
+          :selector="data.elementSelector"
+          @update:selector="updateData({ elementSelector: $event })"
+        />
       </edit-autocomplete>
       <ui-checkbox
         :model-value="data.waitForSelector"
@@ -179,6 +184,7 @@ import { useI18n } from 'vue-i18n';
 import { useToast } from 'vue-toastification';
 import Papa from 'papaparse';
 import { openFilePicker } from '@/utils/helper';
+import SharedElSelectorActions from '@/components/newtab/shared/SharedElSelectorActions.vue';
 import EditAutocomplete from './EditAutocomplete.vue';
 
 const SharedCodemirror = defineAsyncComponent(() =>

+ 20 - 7
src/components/newtab/workflow/edit/EditLoopElements.vue

@@ -35,14 +35,25 @@
           {{ t(`workflow.blocks.loop-elements.actions.${action}`) }}
         </option>
       </ui-select>
-      <ui-input
+      <edit-autocomplete
         v-if="['click-element', 'click-link'].includes(data.loadMoreAction)"
-        :model-value="data.actionElSelector"
-        :label="t('workflow.blocks.base.selector')"
-        placeholder="CSS Selector or XPath"
-        class="mt-2 w-full"
-        @change="updateData({ actionElSelector: $event })"
-      />
+        block
+        class="mt-2"
+        trigger-class="!flex items-end"
+      >
+        <ui-input
+          :model-value="data.actionElSelector"
+          :label="t('workflow.blocks.base.selector')"
+          placeholder="CSS Selector or XPath"
+          class="mr-2 flex-1"
+          autocomplete="off"
+          @change="updateData({ actionElSelector: $event })"
+        />
+        <shared-el-selector-actions
+          :selector="data.actionElSelector"
+          @update:selector="updateData({ actionElSelector: $event })"
+        />
+      </edit-autocomplete>
       <ui-input
         v-if="['click-element', 'scroll'].includes(data.loadMoreAction)"
         :model-value="data.actionElMaxWaitTime"
@@ -76,6 +87,8 @@
 import { onMounted } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { nanoid } from 'nanoid/non-secure';
+import SharedElSelectorActions from '@/components/newtab/shared/SharedElSelectorActions.vue';
+import EditAutocomplete from './EditAutocomplete.vue';
 import EditInteractionBase from './EditInteractionBase.vue';
 
 const props = defineProps({

+ 7 - 2
src/components/newtab/workflow/edit/EditPressKey.vue

@@ -6,15 +6,19 @@
       :placeholder="t('common.description')"
       @change="updateData({ description: $event })"
     />
-    <edit-autocomplete class="mt-2">
+    <edit-autocomplete class="mt-2" trigger-class="!flex items-end">
       <ui-input
         :model-value="data.selector"
-        class="w-full"
+        class="flex-1 mr-2"
         autocomplete="off"
         label="Target element (Optional)"
         placeholder="CSS Selector or XPath"
         @change="updateData({ selector: $event })"
       />
+      <shared-el-selector-actions
+        :selector="data.selector"
+        @update:selector="updateData({ selector: $event })"
+      />
     </edit-autocomplete>
     <ui-select
       :model-value="data.action || 'press-key'"
@@ -78,6 +82,7 @@ import { ref, onBeforeUnmount } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { keyDefinitions } from '@/utils/USKeyboardLayout';
 import { recordPressedKey } from '@/utils/recordKeys';
+import SharedElSelectorActions from '@/components/newtab/shared/SharedElSelectorActions.vue';
 import EditAutocomplete from './EditAutocomplete.vue';
 
 const props = defineProps({

+ 7 - 1
src/components/newtab/workflow/edit/EditSwitchTo.vue

@@ -25,20 +25,26 @@
       block
       hide-empty
       class="mt-2"
+      trigger-class="!flex items-end"
     >
       <ui-input
         :model-value="data.selector"
         :label="t('workflow.blocks.switch-to.iframeSelector')"
         placeholder="CSS Selector or XPath"
         autocomplete="off"
-        class="mb-1 w-full"
+        class="w-full mr-2"
         @change="updateData({ selector: $event })"
       />
+      <shared-el-selector-actions
+        :selector="data.selector"
+        @update:selector="updateData({ selector: $event })"
+      />
     </edit-autocomplete>
   </div>
 </template>
 <script setup>
 import { useI18n } from 'vue-i18n';
+import SharedElSelectorActions from '@/components/newtab/shared/SharedElSelectorActions.vue';
 import EditAutocomplete from './EditAutocomplete.vue';
 
 const props = defineProps({

+ 2 - 0
src/content/blocksHandler/handlerVerifySelector.js

@@ -18,6 +18,8 @@ async function verifySelector(block) {
     behavior: 'smooth',
   });
 
+  await sleep(200);
+
   const divEl = document.createElement('div');
   divEl.style =
     'height: 100%; width: 100%; top: 0; left: 0; background-color: rgb(0 0 0 / 0.3); pointer-events: none; position: fixed; z-index: 99999';

+ 2 - 1
src/content/elementSelector/App.vue

@@ -56,7 +56,8 @@
           @child="selectElementPath('down')"
         />
         <ui-button
-          v-if="state.isSelectBlockElement && state.elSelector"
+          v-if="state.isSelectBlockElement"
+          :disabled="!state.elSelector"
           variant="accent"
           class="w-full mt-4"
           @click="saveSelector"

+ 3 - 1
src/newtab/utils/elementSelector.js

@@ -1,5 +1,5 @@
 import browser from 'webextension-polyfill';
-import { isXPath } from '@/utils/helper';
+import { isXPath, sleep } from '@/utils/helper';
 
 async function getActiveTab() {
   const [tab] = await browser.tabs.query({
@@ -73,6 +73,8 @@ async function verifySelector(data) {
     return result;
   } catch (error) {
     console.error(error);
+    await sleep(1000);
+
     return { notFound: true };
   } finally {
     await makeDashboardFocus();