• Stars
    star
    599
  • Rank 73,104 (Top 2 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 12 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A drop-in shim to allow you to use existing html5 drag'n'drop code with mobile browsers

npmversion license issues size gzippedsize

Polyfill for HTML 5 drag'n'drop

The HTML 5 drag'n'drop API allows you to implement drag'n'drop on most desktop browsers and some mobile browsers.

Unfortunately, you'll notice most mobile browsers don't support it, so no iPad (or Nexus) action for you!

Chrome>=96 on Android>=7 and Safari on iOS/iPadOS>=15 are reported to support drag and drop natively! This means native support for drag and drop is growing but some browsers still need polyfilling. It is advised to keep an eye on caniuse and test for your userbase. In the case of iOS native support and the polyfill seem to be able to coexist without issues.

See #167 for state of drag and drop in iOS/iPad>=15.

Chrome>=96 on Android>=7 behaviour is under investigation.

Luckily, browsers give us enough tools to make it happen ourselves if needed. If you drop this package in your page your existing HTML 5 drag'n'drop code should just work (*almost).

Demos

Demo

Check out the demo to see it in action and monitor the console to see the events firing.

Install

npm

npm install mobile-drag-drop --save

jspm

jspm install npm:mobile-drag-drop

Include

global

<link rel="stylesheet" href="libs/mobile-drag-drop/release/default.css">
<script src="libs/mobile-drag-drop/release/index.min.js"></script>

<!--optional import of scroll behaviour-->
<script src="libs/mobile-drag-drop/release/scroll-behaviour.min.js"></script>

<script>
    // options are optional ;)
    MobileDragDrop.polyfill({
        // use this to make use of the scroll behaviour
        dragImageTranslateOverride: MobileDragDrop.scrollBehaviourDragImageTranslateOverride
    });
</script>

SystemJS/JSPM

System.import("mobile-drag-drop");
// import css if using system-js css loader plugin 
System.import("mobile-drag-drop/default.css!");

ES2015/TypeScript/webpack

import {polyfill} from "mobile-drag-drop";

// optional import of scroll behaviour
import {scrollBehaviourDragImageTranslateOverride} from "mobile-drag-drop/scroll-behaviour";

// options are optional ;)
polyfill({
    // use this to make use of the scroll behaviour
    dragImageTranslateOverride: scrollBehaviourDragImageTranslateOverride
});

Make sure to implement a dragenter-listener! (read here why)

// dragenter listener
(event)=> {
    event.preventDefault();
}

If you're targeting iOS Safari 10.x and higher

// iOS>=10 supports passive event listeners
// but make sure to catch or check passive event listener support
// regarding this code running on other platforms.
window.addEventListener( 'touchmove', function() {}, {passive: false});

See #77 and #124 for details.

webpack/scss

@import "~mobile-drag-drop/default.css";

API & Options

export interface Point {
    x: number;
    y: number;
}

// function signature for the dragImageTranslateOverride hook
export type DragImageTranslateOverrideFn = (
    // corresponding touchmove event
    event: TouchEvent, 
    // the processed touch event viewport coordinates
    hoverCoordinates: Point, 
    // the element under the calculated touch coordinates
    hoveredElement: HTMLElement, 
    // callback for updating the drag image offset
    translateDragImageFn: (offsetX: number, offsetY: number) => void;
) => void;

export interface Config {

    // flag to force the polyfill being applied and not rely on internal feature detection
    forceApply?:boolean;

    // useful for when you want the default drag image but still want to apply
    // some static offset from touch coordinates to drag image coordinates
    // defaults to (0,0)
    dragImageOffset?:Point;

    // if the dragImage shall be centered on the touch coordinates
    // defaults to false
    dragImageCenterOnTouch?:boolean;

    // the drag and drop operation involves some processing. here you can specify in what interval this processing takes place.
    // defaults to 150ms
    iterationInterval?:number;

    // hook for custom logic that decides if a drag operation should start
    dragStartConditionOverride?:( event:TouchEvent ) => boolean;

    // hook for custom logic that can manipulate the drag image translate offset
    dragImageTranslateOverride?:DragImageTranslateOverrideFn;

    // hook for custom logic that can override the default action based on the original touch event when the drag never started
    // be sure to call event.preventDefault() if handling the default action in the override to prevent the browser default.
    defaultActionOverride?:( event:TouchEvent ) => void;

    // Drag action delay on touch devices ("hold to drag" functionality, useful for scrolling draggable items). Defaults to no delay.
    holdToDrag?:number;

    /**
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * THE FOLLOWING OPTIONS ARE ONLY AVAILABLE IN v2.3.0-rc.0
     *
     */

    // function invoked for each touchstart event to determine if and which touched element is detected as "draggable"
    tryFindDraggableTarget?:( event:TouchEvent ) => HTMLElement | undefined;

    // function implementing how a copy of the dragged element is created
    // NOTE! this function is for customizing HOW an element is transformed to a drag image element
    // if you're looking for setting a custom drag image please use [setDragImage()](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setDragImage)
    dragImageSetup?:( element:HTMLElement ) => HTMLElement;

    // function for determining element that is currently hovered while dragging
    // defaults to `document.elementFromPoint()`
    elementFromPoint?:( x:number, y:number ) => Element;

    /**
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     */
}

// invoke for initializing the polyfill => returns true if polyfill is applied
export function polyfill(override?: Config):boolean;

Custom events

When setting the option holdToDrag the draggable element will emit custom events:

  • dnd-poly-dragstart-pending as soon as the touchstart event is detected and a drag operation is about to be started after the delay specified with holdToDrag
  • dnd-poly-dragstart-cancel when the drag operation will not be started due to touchmove, touchend, touchcancel or scroll within the holdToDrag delay.

Those events can be used to visualize the holdToDrag so the user is informed that a drag operation is about to start.

DragImage Customization

If you want to set a custom drag image use setDragImage().

Override the classes that are applied by the polyfill for customizing the drag image appearance and snapback behaviour. Mind the !important.

.dnd-poly-drag-image {
    opacity: .5 !important;
}
/* applied when the drag effect is none and the operation ends */
.dnd-poly-drag-image.dnd-poly-snapback {
    -webkit-transition: -webkit-transform 250ms ease-out !important;
    -moz-transition: -moz-transform 250ms ease-out !important;
    -o-transition: -o-transform 250ms ease-out !important;
    transition: transform 250ms ease-out !important;
}
/* applied always as a base class for drop effect styles */
.dnd-poly-drag-icon {
}

CSS classes are applied to the dragImage-element according to the current drop effect: none, copy, move, link.

There is icons.css which defines default styles and icons. Feel free to use this as a starting point.

<link rel="stylesheet" href="[...]/mobile-drag-drop/icons.css">

Custom drag image setup function

One can also set a custom dragImageSetup() function in the polyfill config. This allows to completely customize the routine used to create a copy of the dragged element.

Checkout the default implementation as a starting point.

Known issues and limitations

  • iFrames are currently not supported. Please see #5 for the current state.

  • :before/:after css pseudo styles can't be copied to the drag image. By default classes are removed on the drag image recursively to avoid side-effects. You can pass a custom dragImageSetup function in the config.

Contributions welcome!

Browser compatibility

Browser Support Known issues
Chrome Native No known issues. More info
Firefox Native No known issues. More info
Safari Native No known issues.
Opera Native Same as Chrome.
Brave Native Same as Chrome.
Internet Explorer 11 Native No known issues.
Edge Native No known issues. More info
Mobile Safari (<iOS 10) Polyfill No known issues.
Mobile Safari (>=iOS 10) Polyfill #77
Mobile Safari (>=iOS 15) Native & Polyfill #167
Chrome on iOS Polyfill See Mobile Safari since it's the same engine inside.
Chrome on Android Polyfill No known issues. Needs investigation regarding native capabilities!
Chrome on touch device Polyfill No known issues. More info
Firefox on touch device Native No known issues.
Firefox on Android Polyfill No known issues.
Amazon Silk Unknown Unknown
Ubuntu Phone Polyfill No known issues.
IEMobile Native Unknown

Chrome: Chrome supports touch devices/events. When run on a desktop touch device like MS Surface it turns on touch events which also disables native drag-and-drop support. Touch events can also be set by a user in chrome://flags to auto, on, off.
There is also a flag for enabling drag-and-drop through touch interaction but only for Windows and the option is off by default. The polyfill still works if this setting is active. We cannot detect if this flag is set so we just stick to applying the polyfill when Chrome is detected with touch events enabled.

Firefox: Touch events can be activated by a user in about:config to 0 (off), 1 (on), 2(auto). As of today (FF39.0) touch behavior is off. When touch events are active drag-and-drop interaction will still work, so no need to polyfill.

Cross-browser differences in HTML5 drag'n'drop API

The drag'n'drop API is not implemented consistently in all browsers. This table is an effort to list all things required to make drag'n'drop work in all browsers and with the polyfill.

Browser dragstart drag dragend dragenter dragover dragleave dragexit
Firefox event.dataTransfer.setData(type, data) effectAllowed,dropEffect effectAllowed,dropEffect
IE11 event.preventDefault() when registered on body
Polyfill event.preventDefault() or dropzone required

empty cells mean there is nothing special to take into account

Polyfill requires dragenter listener

On desktop browsers if no dragenter-handler is registered the drag-operation is silently allowed. Browsers don't implement dropzone-attribute according to caniuse which is why they allow it by default, which violates the spec.

If a handler is set up it has to call event.preventDefault() to allow dropping.

This is pretty bad for the polyfill since JS doesn't allow to check how many listeners were invoked when the event is dispatched, which forces the polyfill to rely on a listener being present calling event.preventDefault() to make it work.

Further notices:

  • FF: If effectAllowed or dropEffect is set in dragstart then dragenter/dragover also need to set it.
  • When using a MS Surface tablet a drag-operation is initiated by touch and hold on a draggable.
  • IE11, Chrome (and all other browsers using the same engine), Firefox scroll automatically when dragging close to a viewport edge.

Baseline recommendations for cross-browser/-platform support:

  • Always set drag data on dragstart by calling event.dataTransfer.setData(type, data).
  • Always handle dragenter-event on possible dropzones if the drop is allowed by calling event.preventDefault().
  • Handle dragover-event on dropzone when the drop is allowed by calling event.preventDefault(), otherwise the drag-operation is aborted.

Contribute

Contributions are welcome.

For more details on development setup see CONTRIBUTING.md

Thanks

To the amazing contributors who've provided massive extensions and fixes to the original.

@rem - who created the original demo used to demo this shim's drop-in nature.

License

MIT License

More Repositories

1

js-to-c

Compiled implementation of Javascript, targeting C (for fun)
HTML
90
star
2

exambuff

My defunct startup, now open-sourced. Please feel free to make your fortune with it :)
PHP
35
star
3

cute

A toy 'reading version' of AngularJS 1.x - understand the magic! :)
JavaScript
30
star
4

angular-js-class

My AngularJS 1.x class - get in touch if you'd like me to teach this at your company/conference/etc
JavaScript
22
star
5

event-source-express-angular-real-time-tutorial

Demonstrating using EventSource with Express, NodeJS and Angular to build a little chat app.
JavaScript
18
star
6

values

Javascript implementation of ValueObjects. Small and easy to mixin to existing code.
JavaScript
16
star
7

d3.angularize

Want a bit of data-binding within a D3 context?
JavaScript
15
star
8

image-deshredder

JavaScript
11
star
9

js-class

My Javascript class - taught at Render Conf & elsewhere. If you'd like me to deliver this for your company/conference, let me know!
JavaScript
10
star
10

gist-of-angular-2

A toy version of Angular 2 to help you understand the magic! :)
JavaScript
10
star
11

backbone-class

Materials for my class on Backbone - presentation and example code
JavaScript
9
star
12

dostring

A Twitter chat bot written in Erlang/OTP/Postgres
Erlang
8
star
13

d3-class

My D3 class - taught at the European Bioinformatics Campus, and White October Events. Get in touch if you'd like me to run this at your company/conference/etc
JavaScript
8
star
14

ts-immutable-record

Type-safe, immutable records for Typescript - via code-generation.
TypeScript
4
star
15

immutable-date

JavaScript
4
star
16

base-lol

Encode binary data as emojis! 0xCAFECAFE -> πŸ’‹πŸ’ΏπŸ’‹πŸ’Ώ.
JavaScript
4
star
17

houses

twedar client / rails for auth - twedar is a machine learning twitter client
Ruby
3
star
18

node-class

JavaScript
3
star
19

misnomer

a tool I wished existed
3
star
20

timruffles.github.io

The source code to my blog
JavaScript
3
star
21

backbone-vo

Value objects for Backbone.js - allows you to use value object semantics to clean up your application's handling of concepts like Periods, Points, Money and Units
JavaScript
3
star
22

simple-angular-skeleton

cos easy things should be easy
JavaScript
3
star
23

defaultmap

Map subclass where `get(k)` returns default values where `k` is not in the map.
JavaScript
3
star
24

proxytron

proxytron: proxying between NodeJS EventEmitters. 100% branch/statement test coverage and zero dependencies.
JavaScript
3
star
25

angular-scroll-manager

Keep your scrolling logic where it belongs - in the view.
JavaScript
3
star
26

twitter_ml_processes

node backend for processing tweets and classifying - twedar is a machine learning twitter client
CoffeeScript
3
star
27

reddit-viz

d3 one on one demo
JavaScript
2
star
28

node-js-postgres-example-code

Example code for the Postgres on Node book
JavaScript
2
star
29

angular-2-js-camp

Angular 2 talk given at JSCamp.ro
JavaScript
2
star
30

problempit

Ruby
2
star
31

blog-unit

Show you readers you care with inline unit tests for your example code
JavaScript
2
star
32

angular-2-class

JavaScript
2
star
33

typed-middleware

Type-safe and explicit middleware for Go via code generation.
Go
2
star
34

angular-2-alpha

Angular 2 intro - code examples in /live-code, talk given at JS-Monthly, 2015
JavaScript
2
star
35

js-todos

Finds TODOs/FIXMEs in JS source code using esprima
JavaScript
2
star
36

code-reads

2
star
37

Cookbook

A quick app to share stuff, has a lazy login mechanism
Ruby
2
star
38

PlSpider

JavaScript
1
star
39

ruby_tower_defence

tower defence engine in ruby, with prototype js frontend
JavaScript
1
star
40

Javascript-Components

JavaScript
1
star
41

PLProc

Picklive Data visualisation, that currently looks like a big spider's web
JavaScript
1
star
42

node-pprint

Printing/logging helpers for testing/development.
JavaScript
1
star
43

fowa-data-viz

JavaScript
1
star
44

game-client-backbone

JavaScript
1
star
45

midi_diff

Show differences between versions of midi files - http://timruffles.github.com/midi_diff
JavaScript
1
star
46

d3-live-viz-demo

JavaScript
1
star
47

js-lisp

a little lisp in JS
JavaScript
1
star
48

js-and-d3-class

Using JS & D3 to create great data-visualisations!
JavaScript
1
star
49

rails-2-devise-template

Rails 2.3 app with devise
Ruby
1
star
50

emf-camp-app-driver

Python
1
star
51

docker-test.sh

scripts for testing docker containers
Shell
1
star
52

tweet_viewer

JavaScript
1
star
53

tweet_data

Ruby
1
star
54

typescript-language-that-could

JavaScript
1
star
55

quadtree-talk

JavaScript
1
star
56

periods

JavaScript
1
star
57

iTerm-scripting

Ruby
1
star
58

js-testing-class

small example
JavaScript
1
star
59

angular-rx-redux-class

TypeScript
1
star
60

d3-dot-net

Article and code example that was part of .NET magazine, issue 257
JavaScript
1
star
61

angularjs-learnable-example-code

JavaScript
1
star
62

CheeseGrater

Scraping Library
Ruby
1
star
63

romans

little game to explore moai
Lua
1
star
64

angular-1.x-right-way

JavaScript
1
star
65

you-probably-dont-want-an-object

talk given at LondonJSConf, 2014
JavaScript
1
star
66

jb

A friendly, pure ascii, language to author JSON in the CLI - the complement to jq
C
1
star
67

math_fun

bits and pieces from OU courses, and general stuff
JavaScript
1
star
68

d3-toys

Toys made in d3
JavaScript
1
star
69

great_tiny_game

My game for http://greattinygamechallenge.tumblr.com/
JavaScript
1
star
70

angular-browserify-example-app

example of how to use browserify to *replace* Angular's module system (i.e you use require() instead of angular.module(), not both)
JavaScript
1
star
71

javascript-code-quality

talk on code quality for javascript
JavaScript
1
star