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

Expose grab method #375

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Expose grab method #375

wants to merge 1 commit into from

Conversation

ben-girardet
Copy link

Exposing the grab method allow developers to initiate a grab movement using custom logic.

This simple change gives powerful freedom to developers in the way they want the drag and drop to operate. In my case I'm now able to add a timeout before dragging can start. Here is my process:

  1. I listen to mousedown and touchstart events on elements I would like to be draggable
  2. This events are received in a shouldLift() method that which start a timeout function
  3. I also listen to mouseup and touchend events. These events are received in a clearShouldLift() method which clear the timeout
  4. In the case the timeout reaches its timing before clearShouldLift() occurs, I fire a .grab(event) in the drake instance, passing along the event received from mousedown or touchstart

I find that exposing the grab method is a minor change increasing the opportunities on the way to use the dragula api.

// FYI: this code is part of an Aurelia View Model
shoudLiftTimeout = null;
shouldLift(event) {
  this.shoudLiftTimeout = setTimeout(() => {
    this.dragApi.grab(event); // dragApi is my drake instance
  }, 1500);
  return true;
}

clearShouldLift(event) {
  if(this.shoudLiftTimeout) clearTimeout(this.shoudLiftTimeout);
  return true;
}

@codeclown
Copy link

Definitely would like this. My use case would be having a handle completely outside the draggable element, which means I'd need to initiate the drag when the external handle is target of mousedown.

@trompx
Copy link

trompx commented Aug 3, 2016

Thanks for this one @ben-girardet

@kristianmandrup
Copy link

kristianmandrup commented Nov 24, 2016

Please merge :) I guess this could also be used to enable grabbing and dragging multiple items?

@rohan-deshpande
Copy link

Hi, I'm trying to implement this, have pulled your commit into my app, but I'm not exactly understanding how the native dragula behaviour is being stopped by this. I can see that you are firing the grab event manually, but doesn't the event need to have its default behaviour prevented somehow? I can't see where you are doing this.

@ben-girardet
Copy link
Author

@rohan-deshpande I use the standard dragula API for everything else but manually grab an element. From there, I continue to manage the behavior with the standard drake instance (this.dragApi) in my exemple above. The only change in the PR is the fact that I can manually call grab(event) because it is exposed.

@rohan-deshpande
Copy link

@ben-girardet Hmm I guess what I'm saying is, Dragula itself fires the grab handler, how are you preventing that default behaviour? In any case I've also made a PR for the latest version of the package which simply restores the delay option #579

@ben-girardet
Copy link
Author

@rohan-deshpande yeah you need to find your workaround for this. So my way of doing this follow this logic:

// this is inside an touch or mouse event when I must determine if I want to grab or not the element, it's not dragula code, just plain HTML5/JS code.

if (this.dragApi && !this.isScrolling) {
  stepEl.classList.add('lifted');
  setTimeout(() => {
    stepEl.classList.remove('lifted');
  }, 200);
  this.lifted = true;
  this.dragApi.grab(event);
  setTimeout(() => {
    this.lifted = false;
  }, 100);
}

The idea here is that I add or remove a "lifted" CSS class in the element depending on timeout value.

Then in the dragula config object, I use this class to allow or not the move:

   this.dragApi = dragula({
      containers: [document.querySelector('steps-container')],
      isContainer: (el) => {
        if (el.id === 'drag-container') return false;
        if (el.classList.contains('drop-step')) return true;
        return false;
      },
      revertOnSpill: true,
      delay: 200,
      mirrorContainer: document.querySelector('#drag-container'),
      moves: (el) => {
        if (this.lifted) {
          this.lifted = false;
          return el.classList.contains('step');
        }
        return false;
      }
    });

Hope this can help you.

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 this pull request may close these issues.

5 participants