Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tried to tweak the options of your new version, not working though #77

Closed
headwindtrend opened this issue Jul 27, 2024 · 30 comments · Fixed by #81
Closed

tried to tweak the options of your new version, not working though #77

headwindtrend opened this issue Jul 27, 2024 · 30 comments · Fixed by #81

Comments

@headwindtrend
Copy link

headwindtrend commented Jul 27, 2024

tried this

    <script type="module">
      import { enableDragDropTouch } from "./drag-drop-touch.esm.min.js";
      enableDragDropTouch(document, document, {isPressHoldMode: true, pressHoldThresholdPixels: 5});
    </script>

doesn't work. anything wrong with my testing code?

@headwindtrend
Copy link
Author

just tried this

    <script type="module">
      import { enableDragDropTouch } from "./drag-drop-touch.esm.min.js";
      enableDragDropTouch(document, document, {isPressHoldMode: true});
    </script>

this one does work. but, it makes me wonder, the pressHoldThresholdPixels must be zero?

@Pomax
Copy link
Member

Pomax commented Jul 27, 2024

Can you unpack what "doesn't work" mean? (e.g. what are you trying to do, and what interaction are you performing so I can try to reproduce that?)

The pressHoldThresholdPixels value is used to determine whether the data associated with a long-press is actually supposed to be interpreted as the start of a drag action or not. The bigger you make the value, the less sensitive to touch move the polyfill is, so the bigger the number, the more your touch input is going to be considered "just a long press" without activating the drag-and-drop polyfill.

(But note that dragThresholdPixels will take precedence, so if that's lower than pressHoldThresholdPixels, dragging should kick in based on that value instead)

Also note that isPressHoldMode "turns off" regular dragging: you now need to first press and hold long enough for the polyfill to go "okay, a long press has happened, now we can decide whether we need to generate drag events or not".

That said, looking at the code for _shouldStartDragging, it's curious that if isPressHoldMode is false, the regular drag threshold gets used, but when it's true, the regular drag threshold still gets considered. That should probably not be the case.

@Pomax
Copy link
Member

Pomax commented Jul 27, 2024

@Bernardo-Castilho the original TS rewrite added _shouldStartDragging as:

_shouldStartDragging(e: TouchEvent) {
let delta = this._getDelta(e);
return delta > this.configuration.dragThresholdPixels ||
(this.configuration.isPressHoldMode && delta >= this.configuration.pressHoldThresholdPixels);
}

but should that be stricter? E.g.

  _shouldStartDragging(e: TouchEvent) {
    let delta = this._getDelta(e);
    if (this.configuration.isPressHoldMode) {
      return delta >= this.configuration.pressHoldThresholdPixels;
    }
    return delta > this.configuration.dragThresholdPixels;
  }

That is, check if we've crossed the pressHoldThresholdPixels threshold if isPressHoldMode is true, and only check dragThresholdPixels is isPressHoldMode is not true?

@Bernardo-Castilho
Copy link
Collaborator

It looks like the original version will use the smaller value between this.configuration.pressHoldThresholdPixels and this.configuration.dragThresholdPixels, while the second version will use one value or the other, depending on the value of this.configuration.isPressHoldMode.

I think I like the second version better.

@headwindtrend
Copy link
Author

Can you unpack what "doesn't work" mean? (e.g. what are you trying to do, and what interaction are you performing so I can try to reproduce that?)

The pressHoldThresholdPixels value is used to determine whether the data associated with a long-press is actually supposed to be interpreted as the start of a drag action or not. The bigger you make the value, the less sensitive to touch move the polyfill is, so the bigger the number, the more your touch input is going to be considered "just a long press" without activating the drag-and-drop polyfill.

(But note that dragThresholdPixels will take precedence, so if that's lower than pressHoldThresholdPixels, dragging should kick in based on that value instead)

Also note that isPressHoldMode "turns off" regular dragging: you now need to first press and hold long enough for the polyfill to go "okay, a long press has happened, now we can decide whether we need to generate drag events or not".

That said, looking at the code for _shouldStartDragging, it's curious that if isPressHoldMode is false, the regular drag threshold gets used, but when it's true, the regular drag threshold still gets considered. That should probably not be the case.

i didn't give any description of what happened hence "doesn't work", my apology. i guess, i was thinking if you use my testing code and try it, you will see what it was. i try my best to describe it here anyhow: when this {isPressHoldMode: true, pressHoldThresholdPixels: 5} is set, "drag" never happened no matter how hard i tried, i.e. press-and-hold for various time (from zero to the point when contextmenu kicks in) and then slide, "drag" just not shown, like, at all.

for the second attempt with this {isPressHoldMode: true} setting alone (i.e. pressHoldThresholdPixels should remain be 0), it "does work". that is, the "drag" happened after a brief press-and-hold and then slide. however, it's working basically the same as when isPressHoldMode is set as false, i.e. i don't really need to press-and-hold to trigger a "drag", even if i swipe (no any press-and-hold, not even a brief one), "drag" still kicks in.

my intented effect: i don't want the "drag" kicking in when i just want to "scroll" the screen by swiping. so i figured i should use isPressHoldMode. and, i also worried that the isPressHoldMode may be too sensitive if pressHoldThresholdPixels is 0, so i tried to tweak it to 5. that's why i started it all. btw, if it's not too much, i would like to see a visual cue when the press-and-hold is long enough (and the pressHoldThresholdPixels condition has also been met) for the "drag" to kick in. better yet, may be, only when my finger slide across the visual cue, the "drag" should therefore really take place.

besides, i also tried this https://bernardo-castilho.github.io/DragDropTouch/drag-drop-touch.esm.min.js instead of this ./drag-drop-touch.esm.min.js, it gave me 404 (Not Found) though.

@Pomax
Copy link
Member

Pomax commented Jul 27, 2024

Ah, thank you, that should be enough for me to see if I can reproduce the same interactions.

As for the 404: the repository changed from https://bernardo-castilho.github.io to https://drag-drop-touch-js.github.io so if you update your URL it should work. That said, github's not a fan of being a CDN (I have no idea why, it's kind of obvious that they are?) so I'm still looking at hosting the library on a "real" CDN soon.

@Pomax
Copy link
Member

Pomax commented Jul 27, 2024

Oh, one more question, because I've noticed different devices doing different things: which device/os/browser combination was this happening for?

@headwindtrend
Copy link
Author

android version 14, and android chrome 125.0.6422.165

@Pomax
Copy link
Member

Pomax commented Jul 27, 2024

Cheers. The most recent Android I have on a device here is Android 13 but that should hopefully still be good enough to replicate this weekend.

@headwindtrend
Copy link
Author

As for the 404: the repository changed from https://bernardo-castilho.github.io to https://drag-drop-touch-js.github.io so if you update your URL it should work.

fyi, i got this Access to script at 'https://drag-drop-touch-js.github.io/DragDropTouch/drag-drop-touch.esm.min.js' from origin 'https://www.youtube.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. error message for loading this https://drag-drop-touch-js.github.io/DragDropTouch/drag-drop-touch.esm.min.js whereas loading this https://bernardo-castilho.github.io/DragDropTouch/DragDropTouch.js old one doesn't have such problem so far.

@Pomax
Copy link
Member

Pomax commented Jul 29, 2024

@Pomax
Copy link
Member

Pomax commented Jul 29, 2024

I've updated the README.md to show the correct URL.

@headwindtrend
Copy link
Author

You want https://drag-drop-touch-js.github.io/dragdroptouch/dist/drag-drop-touch.esm.min.js (note the dist bit)

yes, that's working as it used to be with the correct url.

@Pomax
Copy link
Member

Pomax commented Jul 29, 2024

So I set up a https://drag-drop-touch-js.github.io/dragdroptouch/demo/issue-77 which has your script block in it,

    <script type="module">
      import { enableDragDropTouch } from "./drag-drop-touch.esm.min.js";
      enableDragDropTouch(document, document, {
        isPressHoldMode: true,
        pressHoldThresholdPixels: 5,
      });
    </script>

but if I load that on Android 13 in Chrome 127.0.6533.64 (that's the most recent version available on the play store for me) I can't seem to reproduce the problem you're having. If I tap-and-hold an element (but not the image, that pops up the image inspection context menu) then it changes to the "drag" CSS after a few hundred milliseconds, and then I can drag and drop it on another element to swap their positions.

@headwindtrend
Copy link
Author

that's kind of strange. look, i tried yours on my android device, it does work (as you told), yet, my own testing setup still the same, not working. another strange thing is, when i try yours on my win10 device, it gave me this GET https://drag-drop-touch-js.github.io/dragdroptouch/demo/issue-77/drag-drop-touch.esm.min.js net::ERR_ABORTED 404 (Not Found) error message. and i can't tell if i had that error message on my android device or not (probably not), because i don't have a tool there to see the console. but since touch-drag is working, i believe there is not such error on my android. just don't know why there is 404 on my win10 though in trying yours. anyhow, back to the main issue, my own setup is still not working, would you mind to test it on your side? here is it:

<html>

  <head>
    <script type="module">
      import { enableDragDropTouch } from "https://drag-drop-touch-js.github.io/dragdroptouch/dist/drag-drop-touch.esm.min.js";
      enableDragDropTouch(document, document, {isPressHoldMode: true, pressHoldThresholdPixels: 5});
    </script>

    <script>
      document.addEventListener("dragover", e => {
        e.preventDefault();
      });
      document.addEventListener("drop", e => {
        e.preventDefault();
        document.body.innerText = e.dataTransfer.getData("text/plain");
      });
      document.addEventListener("dragstart", e => {
        e.dataTransfer.setData("text/plain", e.target.href);
      });
    </script>

  </head>

  <body>
    <p>
      window A
    </p>
    <p>
      <a href="#">
        <svg>
          <rect width="300" height="200" style="cursor:pointer;fill:green"/>
          <text x="50%" y="50%" dy=".3em" text-anchor="middle" style="font:bold 20px sans-serif;fill:white">testing</text>
        </svg>
      </a>
    </p>
    <p>
      window B
    </p>
  </body>
</html>

@headwindtrend
Copy link
Author

hmm, is it something about image (including svg?) element?

@headwindtrend
Copy link
Author

hmm, is it something about image (including svg?) element?

but no, i guess. given that this {isPressHoldMode: true} alone does work on my setup (just no need to press-and-hold though).

@Pomax
Copy link
Member

Pomax commented Jul 29, 2024

so here's what I think is going on: Chrome on Android has drag and drop support. It... just works. Testing with https://jsfiddle.net/unh6Lsq0 on my phone, which doesn't load the drag-drop-touch polyfill already works all on its own.

So the reason I saw it work was because I had the wrong URL for the js file in the index.html (as you saw) and I just updated it to the correct one and I'm going to guess that'll actually break things because chrome already works, and the polyfill is now going to interfere with proper drag-and-drop handling.

@Pomax
Copy link
Member

Pomax commented Jul 29, 2024

Hm, with the HTML fixed (network tab shows correct loading of the JS file), things still seem to work on my phone.

@headwindtrend
Copy link
Author

i can't think of anything helpful for you on this im afraid.

@Pomax
Copy link
Member

Pomax commented Jul 29, 2024

I've set up your example as https://drag-drop-touch-js.github.io/dragdroptouch/demo/issue-77b/ (with <!DOCTYPE HTML> at the top so we don't run in quirks mode), and that works on desktop, but not on my phone. I suspect that the <svg> element is indeed a problem here, but I'll do some more digging tomorrow.

@headwindtrend
Copy link
Author

ic. thanks. and looking for your further discovery. cheers.

@Pomax
Copy link
Member

Pomax commented Jul 29, 2024

I've updated the 77b test page so that it can test all three cases (default, isPressHoldMode, and isPressHoldMode with threshold) and it does show the first two working, but the third not, so I'm going to see if I can do some creative localhost server + usb remote debugging to get more information about what's going on here.

@Bernardo-Castilho
Copy link
Collaborator

Bernardo-Castilho commented Jul 29, 2024

I tried this here. As far as I can tell, the problem is related to the fact that a elements behave as img, and are draggable by default. If you want to drag the container element instead, you have to set draggable to false on these elements, e.g.:

<div class="column" draggable="true">
  <header>Images</header>
  <img
    src="https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"
    draggable="false"
    alt="grapefruit"
  />
  <p>
    <a href="#" draggable="false">
      <svg>
        <rect width="100" height="18" style="cursor:pointer;fill:green"/>
        <text x="8%" y="8%" text-anchor="middle" style="font:bold 9px sans-serif;fill:white">testing</text>
      </svg>
    </a>
  </p>
</div>

This works for me.

@Pomax
Copy link
Member

Pomax commented Jul 30, 2024

@Bernardo-Castilho but the question is why it works just fine until you add the threshold value. Both "plain" and "isPressHoldMode-only" modes let me drag the <a> around perfectly fine.

@Bernardo-Castilho
Copy link
Collaborator

Ah, sorry. I didn't realize this was about the isPressHoldMode setting.

I actually never used that, don't understand what it's for.

But looking at the code, it seems like a few methods check for that value:
_shouldHandleMove,
_shouldHandlePressHoldMove, and
_shouldCancelPressHoldMove

My guess is one of these must be preventing the drag operation from starting...

Sorry I couldn't be more helpful.

@Pomax
Copy link
Member

Pomax commented Aug 8, 2024

Right, that took longer to get back to than hoped, but: I can also reproduce this on desktop chrome using touch emulation, and it looks like with debug statements turned on, the delta value is always zero during pressHoldMode, so that's clearly wrong and I'm digging into why atm =)

(the reason it works with pressHoldThresholdPixels set to 0 is because the code checks for delta >= pressHoldThresholdPixels so 0 >= 0 and things work. The moment pressHoldThresholdPixels is more than 0, that check will fail)

@Pomax
Copy link
Member

Pomax commented Aug 8, 2024

As far as I can tell this slipped in with the TS rewrite, which swapped out the old code,

        DragDropTouch.prototype._getDelta = function (e) {
            var p = this._getPoint(e);
            return Math.abs(p.x - this._ptDown.x) + Math.abs(p.y - this._ptDown.y);
        };

with this new code:

  _getDelta(e: TouchEvent) {
    if (!this._ptDown) return 0; // Added by NDP  OK? TODO
    if (this.configuration.isPressHoldMode && !this._ptDown) {
      return 0;
    }
    let p = pointFrom(e);
    return Math.abs(p.x - this._ptDown.x) + Math.abs(p.y - this._ptDown.y);
  }

But this will always return a delta of 0 during long press mode, so that's no bueno if we need to perform a distance-threshold check. If I rewrite it to the following code instead, then the long press threshold is respected again:

  _getDelta(e: TouchEvent) {
    // if there is no active touch we don't need to calculate anything.
    if (!this._ptDown) return 0;

    // Determine how `far` from the event coordinate our
    // original touch coordinate was.
    const { x, y } = this._ptDown;
    const p = pointFrom(e);
    return ((p.x - x) ** 2 + (p.y - y) ** 2) ** 0.5;
  }

@Pomax
Copy link
Member

Pomax commented Aug 8, 2024

Now to figure out how to turn that into a test so we can prevent regressions =D

@Bernardo-Castilho
Copy link
Collaborator

Awesome detective work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants