-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathdrag.js
102 lines (89 loc) · 4.14 KB
/
drag.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
var EmitterB = require("emitter-b")
var proto = require("proto")
// node - The dom node to set as a drag handle
// options
// image - Can take on one of the following possible values:
// false - (Default) No image
// true - The default generated drag image
// string - The path to an image
// imageObject - If this is an Image object, that will be used
// Events:
// start(setData, e) - Emitted when dragging starts. Use setData to set the data for each type.
// setData(type, data) - Sets data for a particular type.
// NOTE: In an attempt mitigate type lowercasing weirdness, capitals will be converted to dash-lowercase *and* lowercase without dashes
// IE NOTE: IE is a piece of shit and doesn't allow any 'type' other than "text" and "url" - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/329509/
// move(pointerPosition, e)
// end(e)
var drag = module.exports = proto(EmitterB, function(superclass) {
this.init = function(node, options) {
var that = this
superclass.init.call(this)
if(!options) options = {}
node.setAttribute("draggable", "true")
var dragInfo = {node:node}, moveHandlerExists = false
this.ifon('start', function() {
node.addEventListener('dragstart', dragInfo.start = function(e) {
if(options.image !== undefined) {
if(options.image !== true) { // if its true, leave the default drag image
if(typeof(options.image) === 'string') {
var image = new Image(options.image)
} else {
var image = options.image
}
e.dataTransfer.setDragImage(image, image.width,image.height)
}
} else {
e.dataTransfer.setDragImage(new Image, 0,0) // no image
}
var dataTransfer = e.dataTransfer
that.emit('start', function(type, string) {
dataTransfer.setData(type, string)
var mappedType = mapFromCamelCase(type)
if(mappedType !== type) {
dataTransfer.setData(mappedType, string)
}
}, e)
if(moveHandlerExists) {
var recentMousePos
document.addEventListener('dragover', dragInfo.docOver = function(e) {
if(recentMousePos === undefined || e.pageX !== recentMousePos.x || e.pageY !== recentMousePos.y) {
recentMousePos = {x:e.pageX, y:e.pageY}
that.emit('move', e)
}
}, true)
node.addEventListener('dragend', function dragendHandler() {
document.removeEventListener('dragover', dragInfo.docOver, true)
dragInfo.node.removeEventListener('dragend', dragendHandler)
})
}
})
})
this.ifon('move', function() {
moveHandlerExists = true
})
this.ifon('end', function() {
node.addEventListener('dragend', dragInfo.end = function(e) {
that.emit('end', e)
})
})
this.ifoff('start', function() {
dragInfo.node.removeEventListener('dragstart', dragInfo.start)
})
this.ifoff('move', function() {
moveHandlerExists = false
if(dragInfo.docOver) document.removeEventListener('dragover', dragInfo.docOver, true)
})
this.ifoff('end', function() {
dragInfo.node.removeEventListener('dragend', dragInfo.end)
})
// deprecated
if(options.start) this.on('start', options.start)
if(options.move) this.on('move', options.move)
if(options.end) this.on('end', options.end)
}
})
function mapFromCamelCase(string) {
return string.replace(/([A-Z])/g, function(match, submatch) { // this is from jss
return '-' + submatch.toLowerCase()
})
}