forked from aosabook/500lines
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdrag.js
112 lines (103 loc) · 4.42 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
103
104
105
106
107
108
109
110
111
112
(function(global){
'use strict';
var dragTarget = null; // Block we're dragging
var dragType = null; // Are we dragging from the menu or from the script?
var scriptBlocks = []; // Blocks in the script, sorted by position
var nextBlock = null; // Block we'll be inserting before
function dragStart(evt){
if (!matches(evt.target, '.block')) return;
if (matches(evt.target, '.menu .block')){
dragType = 'menu';
}else{
dragType = 'script';
}
evt.target.classList.add('dragging');
dragTarget = evt.target;
scriptBlocks = [].slice.call(document.querySelectorAll('.script .block:not(.dragging)'));
// For dragging to take place in Firefox, we have to set this, even if we don't use it
evt.dataTransfer.setData('text/html', evt.target.outerHTML);
if (matches(evt.target, '.menu .block')){
evt.dataTransfer.effectAllowed = 'copy';
}else{
evt.dataTransfer.effectAllowed = 'move';
}
}
function findPosition(evt){
var prevBlock = nextBlock;
nextBlock = null;
var x = evt.clientX;
var y = evt.clientY;
var offset = 15; // pixels cursor can overlap a block by
for (var i = 0; i < scriptBlocks.length; i++){
var block = scriptBlocks[i];
var rect = block.getBoundingClientRect();
if (y < (rect.top + offset)){
nextBlock = block;
break;
}
}
if (prevBlock !== nextBlock){
if (prevBlock){ prevBlock.classList.remove('next'); }
if (nextBlock){ nextBlock.classList.add('next'); }
}
}
function dragEnter(evt){
if (matches(evt.target, '.menu, .script, .content')){
evt.target.classList.add('over');
if (evt.preventDefault) { evt.preventDefault(); }// Necessary. Allows us to drop.
}else{
if (!matches(evt.target, '.menu *, .script *')){
_findAndRemoveClass('over');
evt.target.classList.remove('over');
}
}
return false;
}
function dragOver(evt){
if (!matches(evt.target, '.menu, .menu *, .script, .script *, .content')) return;
if (evt.preventDefault) { evt.preventDefault(); } // Necessary. Allows us to drop.
if (dragType === 'menu'){
evt.dataTransfer.dropEffect = 'copy'; // See the section on the DataTransfer object.
}else{
evt.dataTransfer.dropEffect = 'move';
}
return false;
}
function drop(evt){
if (!matches(evt.target, '.menu, .menu *, .script, .script *')) return;
var dropTarget = closest(evt.target, '.script .container, .menu, .script');
findPosition(evt);
var dropType = 'script';
if (matches(dropTarget, '.menu')){ dropType = 'menu'; }
if (evt.stopPropagation) { evt.stopPropagation(); } // stops the browser from redirecting.
if (dragType === 'script' && dropType === 'menu'){
trigger('blockRemoved', dragTarget.parentElement, dragTarget);
dragTarget.parentElement.removeChild(dragTarget);
}else if (dragType ==='script' && dropType === 'script'){
if (nextBlock){ dropTarget = nextBlock.parentElement; }
dropTarget.insertBefore(dragTarget, nextBlock);
trigger('blockMoved', dropTarget, dragTarget);
}else if (dragType === 'menu' && dropType === 'script'){
var newNode = dragTarget.cloneNode(true);
newNode.classList.remove('dragging');
if (nextBlock){ dropTarget = nextBlock.parentElement; }
dropTarget.insertBefore(newNode, nextBlock);
trigger('blockAdded', dropTarget, newNode);
}
}
function _findAndRemoveClass(klass){
var elem = document.querySelector('.' + klass);
if (elem){ elem.classList.remove(klass); }
}
function dragEnd(evt){
_findAndRemoveClass('dragging');
_findAndRemoveClass('over');
_findAndRemoveClass('next');
}
document.addEventListener('dragstart', dragStart, false);
document.addEventListener('dragenter', dragEnter, false);
document.addEventListener('dragover', dragOver, false);
document.addEventListener('drag', function(){}, false);
document.addEventListener('drop', drop, false);
document.addEventListener('dragend', dragEnd, false);
})(window);