Ver Fonte

fix: limit drag-reordering to sort=exec

...also hook the parent to reduce the amount of listeners
tophf há 3 anos atrás
pai
commit
28d79430d2

+ 21 - 14
src/options/utils/dragging.js

@@ -1,4 +1,5 @@
 
 
+const SCRIPT = '.script';
 const SCROLL_GAP = 50;
 const SCROLL_GAP = 50;
 // px per one 60fps frame so the max is ~1200px per second (~one page)
 // px per one 60fps frame so the max is ~1200px per second (~one page)
 const MAX_SCROLL_SPEED = 20;
 const MAX_SCROLL_SPEED = 20;
@@ -30,6 +31,7 @@ let offsetX;
 let offsetY;
 let offsetY;
 let original;
 let original;
 let parent;
 let parent;
+let parentOnDrop;
 let scrollEdgeTop;
 let scrollEdgeTop;
 let scrollEdgeBottom;
 let scrollEdgeBottom;
 let scrollTimer;
 let scrollTimer;
@@ -37,20 +39,20 @@ let scrollSpeed;
 let scrollTimestamp;
 let scrollTimestamp;
 let xyCache;
 let xyCache;
 
 
-/**
- * @param {Element} el
- * @param {function(from,to)} onDrop
- */
-export default function enableDragging(el, { onDrop }) {
-  if (!parent) {
-    parent = el.parentElement;
-  }
-  el::on(eventNames.start, isTouch ? onTouchStart : onDragStart);
-  el::on(DROP_EVENT_RELAY, () => onDrop(index, lastIndex));
+/** @this {?} TabInstalled */
+export default function toggleDragging(state) {
+  parent = this.$refs.scriptList;
+  parentOnDrop = this.moveScript;
+  parent::(state ? on : off)(eventNames.start, isTouch ? onTouchStart : onDragStart);
+  parent::(state ? on : off)(DROP_EVENT_RELAY, onDrop);
+}
+
+function onDrop() {
+  parentOnDrop(index, lastIndex);
 }
 }
 
 
 function onTouchStart(e) {
 function onTouchStart(e) {
-  original = this;
+  if (!scriptFromEvent(e)) return;
   longPressEvent = e;
   longPressEvent = e;
   longPressTimer = setTimeout(onTouchMoveDetect, LONGPRESS_DELAY, 'timer');
   longPressTimer = setTimeout(onTouchMoveDetect, LONGPRESS_DELAY, 'timer');
   document::on(eventNames.move, onTouchMoveDetect);
   document::on(eventNames.move, onTouchMoveDetect);
@@ -76,7 +78,7 @@ function onTouchEndDetect() {
 }
 }
 
 
 function onDragStart(e) {
 function onDragStart(e) {
-  original = this;
+  if (!scriptFromEvent(e)) return;
   if (e.cancelable) e.preventDefault();
   if (e.cancelable) e.preventDefault();
   const { clientX: x, clientY: y } = e.touches?.[0] || e;
   const { clientX: x, clientY: y } = e.touches?.[0] || e;
   const rect = original.getBoundingClientRect();
   const rect = original.getBoundingClientRect();
@@ -105,7 +107,7 @@ function onDragStart(e) {
 function onDragMouseMove(e) {
 function onDragMouseMove(e) {
   const { clientX: x, clientY: y, target } = e.touches?.[0] || e;
   const { clientX: x, clientY: y, target } = e.touches?.[0] || e;
   let moved;
   let moved;
-  const hovered = isTouch ? scriptFromPoint(x, y) : target.closest?.('.script');
+  const hovered = isTouch ? scriptFromPoint(x, y) : target.closest?.(SCRIPT);
   // FF bug: despite placeholder having `pointer-events:none` it's still reported in `target`
   // FF bug: despite placeholder having `pointer-events:none` it's still reported in `target`
   if (hovered && hovered !== original) {
   if (hovered && hovered !== original) {
     const rect = hovered.getBoundingClientRect();
     const rect = hovered.getBoundingClientRect();
@@ -187,6 +189,11 @@ function stopPropagation(e) {
 // touch devices are usually slooooow so touchmove causes jank due to frequent elementFromPoint
 // touch devices are usually slooooow so touchmove causes jank due to frequent elementFromPoint
 function scriptFromPoint(x, y) {
 function scriptFromPoint(x, y) {
   const key = `${x}:${y}`;
   const key = `${x}:${y}`;
-  const el = xyCache[key] || (xyCache[key] = document.elementFromPoint(x, y)?.closest('.script'));
+  const el = xyCache[key] || (xyCache[key] = document.elementFromPoint(x, y)?.closest(SCRIPT));
   return el;
   return el;
 }
 }
+
+function scriptFromEvent(e) {
+  original = e.target.closest(SCRIPT);
+  return original;
+}

+ 9 - 12
src/options/views/script-item.vue

@@ -9,7 +9,6 @@
       hotkeys: focused && showHotkeys,
       hotkeys: focused && showHotkeys,
     }"
     }"
     :tabIndex="tabIndex"
     :tabIndex="tabIndex"
-    :draggable="draggable"
     @focus="onFocus"
     @focus="onFocus"
     @blur="onBlur">
     @blur="onBlur">
     <div class="script-icon hidden-xs">
     <div class="script-icon hidden-xs">
@@ -19,10 +18,8 @@
     </div>
     </div>
     <div class="script-info flex ml-1c">
     <div class="script-info flex ml-1c">
       <span class="script-order" v-text="script.props.position"/>
       <span class="script-order" v-text="script.props.position"/>
-      <!-- eslint-disable-next-line vue/require-component-is -->
-      <component class="script-name ellipsis flex-auto" v-bind="viewTable
-        ? { is: 'a', href: url, tabIndex }
-        : { is: 'span' }">{{script.$cache.name}}</component>
+      <component :is="nameProps.is" class="script-name ellipsis flex-auto"
+                 v-bind="nameProps">{{script.$cache.name}}</component>
       <template v-if="canRender">
       <template v-if="canRender">
         <tooltip v-if="author" :content="i18n('labelAuthor') + script.meta.author"
         <tooltip v-if="author" :content="i18n('labelAuthor') + script.meta.author"
                  class="script-author ml-1c hidden-sm"
                  class="script-author ml-1c hidden-sm"
@@ -132,14 +129,12 @@ import Tooltip from 'vueleton/lib/tooltip/bundle';
 import { getLocaleString, formatTime } from '#/common';
 import { getLocaleString, formatTime } from '#/common';
 import Icon from '#/common/ui/icon';
 import Icon from '#/common/ui/icon';
 import { keyboardService, isInput, toggleTip } from '#/common/keyboard';
 import { keyboardService, isInput, toggleTip } from '#/common/keyboard';
-import enableDragging from '../utils/dragging';
 
 
 const itemMargin = 8;
 const itemMargin = 8;
 
 
 export default {
 export default {
   props: [
   props: [
     'script',
     'script',
-    'draggable',
     'visible',
     'visible',
     'viewTable',
     'viewTable',
     'focused',
     'focused',
@@ -212,6 +207,13 @@ export default {
     url() {
     url() {
       return `#scripts/${this.script.props.id}`;
       return `#scripts/${this.script.props.id}`;
     },
     },
+    nameProps() {
+      return this.viewTable
+        /* We disable native dragging on name to avoid confusion with exec re-ordering.
+         * Users who want to open a new tab via dragging the link can use the icon. */
+        ? { is: 'a', href: this.url, tabIndex: this.tabIndex, draggable: false }
+        : { is: 'span' };
+    },
   },
   },
   watch: {
   watch: {
     visible(visible) {
     visible(visible) {
@@ -237,11 +239,6 @@ export default {
       }
       }
     },
     },
   },
   },
-  mounted() {
-    enableDragging(this.$el, {
-      onDrop: (from, to) => this.$emit('move', { from, to }),
-    });
-  },
   methods: {
   methods: {
     onRemove() {
     onRemove() {
       this.$emit('remove', this.script);
       this.$emit('remove', this.script);

+ 7 - 3
src/options/views/tab-installed.vue

@@ -120,7 +120,7 @@
           :focused="selectedScript === script"
           :focused="selectedScript === script"
           :showHotkeys="showHotkeys"
           :showHotkeys="showHotkeys"
           :script="script"
           :script="script"
-          :draggable="!showRecycle && filters.sort.value === 'exec'"
+          :draggable="draggable"
           :visible="index < batchRender.limit"
           :visible="index < batchRender.limit"
           :viewTable="filters.viewTable"
           :viewTable="filters.viewTable"
           :hotkeys="scriptHotkeys"
           :hotkeys="scriptHotkeys"
@@ -128,7 +128,6 @@
           @restore="handleActionRestore"
           @restore="handleActionRestore"
           @toggle="handleActionToggle"
           @toggle="handleActionToggle"
           @update="handleActionUpdate"
           @update="handleActionUpdate"
-          @move="moveScript"
           @scrollDelta="handleSmoothScroll"
           @scrollDelta="handleSmoothScroll"
           @tiptoggle.native="showHotkeys = !showHotkeys"
           @tiptoggle.native="showHotkeys = !showHotkeys"
         />
         />
@@ -156,6 +155,7 @@ import { loadData } from '#/options';
 import ScriptItem from './script-item';
 import ScriptItem from './script-item';
 import Edit from './edit';
 import Edit from './edit';
 import { store } from '../utils';
 import { store } from '../utils';
+import toggleDragging from '../utils/dragging';
 
 
 const filterOptions = {
 const filterOptions = {
   sort: {
   sort: {
@@ -281,6 +281,7 @@ export default {
     };
     };
   },
   },
   watch: {
   watch: {
+    draggable: toggleDragging,
     search: 'scheduleSearch',
     search: 'scheduleSearch',
     'filters.sort.value': 'updateLater',
     'filters.sort.value': 'updateLater',
     'filters.showEnabledFirst': 'updateLater',
     'filters.showEnabledFirst': 'updateLater',
@@ -301,6 +302,9 @@ export default {
     },
     },
   },
   },
   computed: {
   computed: {
+    draggable() {
+      return !this.showRecycle && filters.sort.value === 'exec';
+    },
     currentSortCompare() {
     currentSortCompare() {
       return filterOptions.sort[filters.sort.value]?.compare;
       return filterOptions.sort[filters.sort.value]?.compare;
     },
     },
@@ -368,7 +372,7 @@ export default {
         if (err) showMessage({ text: err });
         if (err) showMessage({ text: err });
       }
       }
     },
     },
-    async moveScript({ from, to }) {
+    async moveScript(from, to) {
       if (from === to) return;
       if (from === to) return;
       const scripts = this.filteredScripts;
       const scripts = this.filteredScripts;
       const allScripts = store.scripts;
       const allScripts = store.scripts;