comparison src/dad.js @ 0:8f4df159f06b

start public repo
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 11 Jul 2025 20:57:49 -0600
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:8f4df159f06b
1 'use strict';
2
3 let dad = {};
4
5 {
6 // override these if needed
7 dad.whatToDrag = function(draggable) {
8 return draggable;
9 };
10 dad.onStart = function(event) {};
11 dad.onEnter = function(event) {};
12 dad.onLeave = function(event) {};
13 dad.onDrop = function(event) {};
14 dad.onDropped = function(event) {};
15
16
17 let original = null;
18 let dragging = null;
19 let dropzone = null;
20 let touchX, touchY;
21
22 function isIn(x,y,rect) {
23 return rect.x <= x && x <= rect.x+rect.width && rect.y <= y && y <= rect.y+rect.height;
24 }
25
26 function myEvent(mouseEvent) {
27 return {
28 original: original,
29 dragging: dragging,
30 dropzone: dropzone,
31 mouseEvent: mouseEvent,
32 };
33 }
34
35 function onMouseMove(event) {
36 {
37 event.preventDefault();
38 let rect = dragging.getBoundingClientRect();
39 dragging.style.left = `${rect.x+event.movementX}px`;
40 let y = rect.y + event.movementY;
41 if( y < 0 ) {
42 window.scrollBy( 0, y );
43 } else if( y + rect.height > window.innerHeight ) {
44 window.scrollBy( 0, y + rect.height - window.innerHeight );
45 }
46 dragging.style.top = `${y}px`;
47 }
48 {
49 let x = event.clientX;
50 let y = event.clientY;
51 if( !(dropzone && isIn(x,y,dropzone.getBoundingClientRect())) ) {
52 if( dropzone ) {
53 dad.onLeave(myEvent(event));
54 dropzone = null;
55 }
56 let dropzones = document.querySelectorAll('[dad-dropzone]');
57 for( let i=0; i<dropzones.length; i++ ) {
58 let dz = dropzones[i];
59 if( dz === dragging )
60 continue;
61 if( isIn(x,y,dz.getBoundingClientRect()) ) {
62 let old = dropzone;
63 dropzone = dz;
64 let f = dad.onEnter(myEvent(event));
65 if( f === false )
66 dropzone = old;
67 else
68 break;
69 }
70 }
71 }
72 }
73 }
74
75 function onTouchMove(event) {
76 let touches = event.touches;
77 if( touches.length !== 1 )
78 return;
79 let touch = touches[0];
80 let x = touch.clientX;
81 let y = touch.clientY;
82 event.clientX = x;
83 event.clientY = y;
84 event.movementX = x - touchX;
85 event.movementY = y - touchY;
86 touchX = x;
87 touchY = y;
88 onMouseMove(event);
89 }
90
91 function onMouseUp(event) {
92 dad.onDrop(myEvent(event));
93 if( dropzone ) {
94 dad.onLeave(myEvent(event));
95 }
96 original.removeAttribute('dad-original');
97 dragging.parentNode.removeChild(dragging);
98 document.removeEventListener('mousemove',onMouseMove);
99 document.removeEventListener('mouseup',onMouseUp);
100 document.removeEventListener('touchmove',onTouchMove);
101 document.removeEventListener('touchend',onMouseUp);
102 original.scrollIntoViewIfNeeded(false);
103 let droppedEvent = {
104 original: original,
105 };
106 original = null;
107 dragging = null;
108 dropzone = null;
109 dad.onDropped(droppedEvent);
110 }
111
112 function start(event) {
113 original = dad.whatToDrag(event.target);
114 dragging = original.cloneNode(true);
115 original.setAttribute('dad-original','');
116 dragging.setAttribute('dad-dragging','');
117 let rect = original.getBoundingClientRect();
118 dragging.style.left = `${rect.x}px`;
119 dragging.style.top = `${rect.y}px`;
120 dragging.style.width = `${rect.width}px`;
121 dragging.style.height = `${rect.height}px`;
122 original.parentNode.appendChild(dragging);
123 dad.onStart(myEvent(event));
124 }
125
126 function onMouseDown(event) {
127 start(event);
128 document.addEventListener('mousemove',onMouseMove);
129 document.addEventListener('mouseup',onMouseUp);
130 }
131
132 function onTouchStart(event) {
133 event.preventDefault();
134 start(event);
135 let touches = event.touches;
136 if( touches.length !== 1 )
137 return;
138 let touch = touches[0];
139 touchX = touch.clientX;
140 touchY = touch.clientY;
141 document.addEventListener('touchmove',onTouchMove);
142 document.addEventListener('touchend',onMouseUp);
143 }
144
145 dad.setDraggable = function(el) {
146 el.setAttribute('dad-drag','');
147 el.setAttribute('draggable','false');
148 el.addEventListener('mousedown',onMouseDown);
149 el.addEventListener('touchstart',onTouchStart);
150 };
151
152 dad.setDropzone = function(el) {
153 el.setAttribute('dad-dropzone','');
154 };
155 }