Browse Source

feat(editor): add EditTriggerEvent component

Ahmad Kholid 3 years ago
parent
commit
1af48262a1

+ 4 - 2
src/components/newtab/workflow/WorkflowEditBlock.vue

@@ -1,6 +1,6 @@
 <template>
-  <div class="px-4 overflow-auto scroll">
-    <div class="sticky top-0 bg-white border-b border-gray-100 pb-4 mb-4">
+  <div class="px-4 overflow-auto scroll pb-1">
+    <div class="sticky top-0 z-20 bg-white border-b border-gray-100 pb-4 mb-4">
       <button class="mr-2 align-middle" @click="$emit('close')">
         <v-remixicon name="riArrowLeftLine" />
       </button>
@@ -20,6 +20,7 @@ import { computed } from 'vue';
 import EditTrigger from './edit/EditTrigger.vue';
 import EditGetText from './edit/EditGetText.vue';
 import EditTextInput from './edit/EditTextInput.vue';
+import EditTriggerEvent from './edit/EditTriggerEvent.vue';
 import EditScrollElement from './edit/EditScrollElement.vue';
 import EditAttributeValue from './edit/EditAttributeValue.vue';
 import EditInteractionBase from './edit/EditInteractionBase.vue';
@@ -29,6 +30,7 @@ export default {
     EditTrigger,
     EditGetText,
     EditTextInput,
+    EditTriggerEvent,
     EditScrollElement,
     EditAttributeValue,
     EditInteractionBase,

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

@@ -1,4 +1,5 @@
 <template>
+  <slot name="prepend" />
   <ui-textarea
     :model-value="data.description"
     autoresize

+ 97 - 0
src/components/newtab/workflow/edit/EditTriggerEvent.vue

@@ -0,0 +1,97 @@
+<template>
+  <edit-interaction-base v-bind="{ data }" @change="updateData">
+    <ui-select
+      :model-value="data.eventName"
+      class="w-full mt-2"
+      placeholder="Select event"
+      @change="handleEventChange"
+    >
+      <option v-for="event in eventList" :key="event.id" :value="event.id">
+        {{ event.name }}
+      </option>
+    </ui-select>
+    <button
+      v-if="componentName"
+      class="mb-2 block w-full text-left mt-4 focus:ring-0"
+      @click="showOptions = !showOptions"
+    >
+      <v-remixicon
+        name="riArrowLeftSLine"
+        class="mr-1 transition-transform align-middle inline-block -ml-1"
+        :rotate="showOptions ? 270 : 180"
+      />
+      <span class="align-middle">Options</span>
+    </button>
+    <transition-expand>
+      <div v-if="showOptions && componentName">
+        <component
+          :is="componentName"
+          :params="params"
+          @update="updateParams"
+        />
+      </div>
+    </transition-expand>
+  </edit-interaction-base>
+</template>
+<script>
+import TriggerEventMouse from './TriggerEventMouse.vue';
+import TriggerEventTouch from './TriggerEventTouch.vue';
+import TriggerEventWheel from './TriggerEventWheel.vue';
+import TriggerEventKeyboard from './TriggerEventKeyboard.vue';
+
+export default {
+  components: {
+    TriggerEventMouse,
+    TriggerEventWheel,
+    TriggerEventTouch,
+    TriggerEventKeyboard,
+  },
+};
+</script>
+<script setup>
+/* eslint-disable */
+import { ref } from 'vue';
+import { eventList } from '@/utils/shared';
+import EditInteractionBase from './EditInteractionBase.vue';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const eventComponents = {
+  'mouse-event': 'TriggerEventMouse',
+  'focus-event': '',
+  'touch-event': 'TriggerEventTouch',
+  'keyboard-event': 'TriggerEventKeyboard',
+  'wheel-event': 'TriggerEventWheel',
+};
+
+const componentName = ref(eventComponents[props.data.eventType]);
+const params = ref(props.data.eventParams);
+const showOptions = ref(false);
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+function updateParams(value) {
+  params.value = value;
+  updateData({ eventParams: value });
+}
+function handleEventChange(value) {
+  const eventType = eventList.find(({ id }) => id === value).type;
+  const payload = { eventName: value, eventType };
+
+  componentName.value = eventComponents[eventType];
+
+  if (eventType !== props.eventType) {
+    payload.eventParams = {};
+    params.value = {};
+  }
+
+  updateData(payload);
+}
+</script>

+ 54 - 0
src/components/newtab/workflow/edit/TriggerEventKeyboard.vue

@@ -0,0 +1,54 @@
+<template>
+  <div class="grid gap-2 grid-cols-2">
+    <ui-checkbox
+      v-for="item in ['altKey', 'ctrlKey', 'metaKey', 'shiftKey']"
+      :key="item"
+      v-model="defaultParams[item]"
+    >
+      {{ item }}
+    </ui-checkbox>
+  </div>
+  <div class="flex items-center mt-3 space-x-2">
+    <ui-input v-model="defaultParams.code" class="flex-1" label="code" />
+    <ui-input v-model="defaultParams.key" class="flex-1" label="key" />
+  </div>
+  <ui-checkbox v-model="defaultParams.repeat" class="mt-4">
+    Repeat
+  </ui-checkbox>
+</template>
+<script setup>
+import { shallowReactive, watch, onMounted } from 'vue';
+import { objectHasKey } from '@/utils/helper';
+
+const props = defineProps({
+  params: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update']);
+
+const defaultParams = shallowReactive({
+  altKey: false,
+  ctrlKey: false,
+  metaKey: false,
+  shiftKey: false,
+  code: '',
+  key: '',
+  repat: false,
+});
+
+watch(
+  defaultParams,
+  (value) => {
+    emit('update', value);
+  },
+  { deep: true }
+);
+
+onMounted(() => {
+  Object.entries(props.params).forEach(([key, value]) => {
+    if (objectHasKey(defaultParams, key)) defaultParams[key] = value;
+  });
+});
+</script>

+ 95 - 0
src/components/newtab/workflow/edit/TriggerEventMouse.vue

@@ -0,0 +1,95 @@
+<template>
+  <div class="grid gap-2 grid-cols-2">
+    <ui-checkbox
+      v-for="item in ['altKey', 'ctrlKey', 'metaKey', 'shiftKey']"
+      :key="item"
+      v-model="defaultParams[item]"
+    >
+      {{ item }}
+    </ui-checkbox>
+  </div>
+  <ui-select
+    v-model.number="defaultParams.button"
+    class="mt-2 w-full"
+    label="Button"
+  >
+    <option v-for="button in buttons" :key="button.id" :value="button.id">
+      {{ button.name }}
+    </option>
+  </ui-select>
+  <div
+    v-for="items in posGroups"
+    :key="items[0]"
+    class="flex items-center space-x-2 mt-2"
+  >
+    <ui-input
+      v-model.number="defaultParams[items[0]]"
+      type="number"
+      class="flex-1"
+      :label="items[0]"
+    />
+    <ui-input
+      v-model.number="defaultParams[items[1]]"
+      type="number"
+      class="flex-1"
+      :label="items[1]"
+    />
+  </div>
+</template>
+<script setup>
+import { shallowReactive, watch, onMounted } from 'vue';
+import { objectHasKey } from '@/utils/helper';
+
+const props = defineProps({
+  params: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update']);
+
+const buttons = [
+  { id: 0, name: 'Left click' },
+  { id: 1, name: 'Middle click' },
+  { id: 2, name: 'Right click' },
+];
+const posGroups = [
+  ['clientX', 'clientY'],
+  ['movementX', 'movementY'],
+  ['offsetX', 'offsetY'],
+  ['pageX', 'pageY'],
+  ['screenX', 'screenY'],
+];
+
+const defaultParams = shallowReactive({
+  altKey: false,
+  button: 0,
+  clientX: 0,
+  clientY: 0,
+  ctrlKey: false,
+  metaKey: false,
+  shiftKey: false,
+  movementX: 0,
+  movementY: 0,
+  offsetX: 0,
+  offsetY: 0,
+  pageX: 0,
+  pageY: 0,
+  screenX: 0,
+  screenY: 0,
+});
+
+watch(
+  defaultParams,
+  (value) => {
+    emit('update', value);
+  },
+  { deep: true }
+);
+
+onMounted(() => {
+  Object.entries(props.params).forEach(([key, value]) => {
+    if (objectHasKey(defaultParams, key)) defaultParams[key] = value;
+  });
+});
+</script>

+ 44 - 0
src/components/newtab/workflow/edit/TriggerEventTouch.vue

@@ -0,0 +1,44 @@
+<template>
+  <div class="grid gap-2 grid-cols-2">
+    <ui-checkbox
+      v-for="item in ['altKey', 'ctrlKey', 'metaKey', 'shiftKey']"
+      :key="item"
+      v-model="defaultParams[item]"
+    >
+      {{ item }}
+    </ui-checkbox>
+  </div>
+</template>
+<script setup>
+import { shallowReactive, watch, onMounted } from 'vue';
+import { objectHasKey } from '@/utils/helper';
+
+const props = defineProps({
+  params: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update']);
+
+const defaultParams = shallowReactive({
+  altKey: false,
+  ctrlKey: false,
+  metaKey: false,
+  shiftKey: false,
+});
+
+watch(
+  defaultParams,
+  (value) => {
+    emit('update', value);
+  },
+  { deep: true }
+);
+
+onMounted(() => {
+  Object.entries(props.params).forEach(([key, value]) => {
+    if (objectHasKey(defaultParams, key)) defaultParams[key] = value;
+  });
+});
+</script>

+ 44 - 0
src/components/newtab/workflow/edit/TriggerEventWheel.vue

@@ -0,0 +1,44 @@
+<template>
+  <div class="grid gap-2 grid-cols-2">
+    <ui-input v-model="defaultParams.deltaX" type="number" label="deltaX" />
+    <ui-input v-model="defaultParams.deltaY" type="number" label="deltaY" />
+    <ui-input
+      v-model="defaultParams.deltaX"
+      type="number"
+      class="col-span-2"
+      label="deltaZ"
+    />
+  </div>
+</template>
+<script setup>
+import { shallowReactive, watch, onMounted } from 'vue';
+import { objectHasKey } from '@/utils/helper';
+
+const props = defineProps({
+  params: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update']);
+
+const defaultParams = shallowReactive({
+  deltaX: 0,
+  deltaY: 0,
+  deltaZ: 0,
+});
+
+watch(
+  defaultParams,
+  (value) => {
+    emit('update', value);
+  },
+  { deep: true }
+);
+
+onMounted(() => {
+  Object.entries(props.params).forEach(([key, value]) => {
+    if (objectHasKey(defaultParams, key)) defaultParams[key] = value;
+  });
+});
+</script>

+ 2 - 0
src/components/ui/UiInput.vue

@@ -99,6 +99,8 @@ export default {
 
       if (props.modelModifiers.lowercase) {
         value = value.toLocaleLowerCase();
+      } else if (props.modelModifiers.number) {
+        value = +value;
       }
 
       emit('update:modelValue', value);

+ 18 - 4
src/components/ui/UiSelect.vue

@@ -1,6 +1,10 @@
 <template>
   <div :class="{ 'inline-block': !block }" class="ui-select cursor-pointer">
-    <label v-if="label" :for="selectId" class="text-gray-200 text-sm ml-2">
+    <label
+      v-if="label"
+      :for="selectId"
+      class="text-gray-600 dark:text-gray-200 text-sm ml-2"
+    >
       {{ label }}
     </label>
     <div class="ui-select__content flex items-center w-full block relative">
@@ -63,6 +67,10 @@ export default {
       type: String,
       default: '',
     },
+    modelModifiers: {
+      type: Object,
+      default: () => ({}),
+    },
     block: Boolean,
     showDetail: Boolean,
   },
@@ -70,9 +78,15 @@ export default {
   setup(props, { emit }) {
     const selectId = useComponentId('select');
 
-    function emitValue({ target }) {
-      emit('update:modelValue', target.value);
-      emit('change', target.value);
+    function emitValue(event) {
+      let { value } = event.target;
+
+      if (props.modelModifiers.number) {
+        value = +value;
+      }
+
+      emit('update:modelValue', value);
+      emit('change', value);
     }
 
     return {

+ 4 - 0
src/utils/helper.js

@@ -1,3 +1,7 @@
+export function objectHasKey(obj, key) {
+  return Object.prototype.hasOwnProperty.call(obj, key);
+}
+
 export function debounce(callback, time = 200) {
   let interval;
 

+ 23 - 4
src/utils/shared.js

@@ -173,11 +173,11 @@ export const tasks = {
     disableEdit: true,
     data: {},
   },
-  'trigger-element-events': {
-    name: 'Trigger element events',
+  'trigger-event': {
+    name: 'Trigger event',
     icon: 'riLightbulbFlashLine',
     component: 'BlockBasic',
-    editComponent: 'EditTrigger',
+    editComponent: 'EditTriggerEvent',
     category: 'interaction',
     inputs: 1,
     outputs: 1,
@@ -187,7 +187,9 @@ export const tasks = {
       description: '',
       selector: '',
       multiple: false,
-      events: [],
+      eventName: '',
+      eventType: '',
+      eventParams: {},
     },
   },
   comparison: {
@@ -245,3 +247,20 @@ export const categories = {
     color: 'bg-blue-200',
   },
 };
+
+export const eventList = [
+  { id: 'click', name: 'Click', type: 'mouse-event' },
+  { id: 'dblclick', name: 'Double Click', type: 'mouse-event' },
+  { id: 'mouseup', name: 'Mouseup', type: 'mouse-event' },
+  { id: 'mousedown', name: 'Mousedown', type: 'mouse-event' },
+  { id: 'focus', name: 'Focus', type: 'focus-event' },
+  { id: 'blur', name: 'Blur', type: 'focus-event' },
+  { id: 'touchstart', name: 'Touch start', type: 'touch-event' },
+  { id: 'touchend', name: 'Touch end', type: 'touch-event' },
+  { id: 'touchmove', name: 'Touch move', type: 'touch-event' },
+  { id: 'touchcancel', name: 'Touch cancel', type: 'touch-event' },
+  { id: 'keydown', name: 'Keydown', type: 'keyboard-event' },
+  { id: 'keyup', name: 'Keyup', type: 'keyboard-event' },
+  { id: 'keypress', name: 'Keypress', type: 'keyboard-event' },
+  { id: 'wheel', name: 'Wheel', type: 'wheel-event' },
+];