summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/mdnd/Moveable.js
blob: 43eebf2f3c00692daae01db61cac047d1f4a0f86 (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
//>>built
define("dojox/mdnd/Moveable", [
	"dojo/_base/kernel",
	"dojo/_base/array",
	"dojo/_base/connect",
	"dojo/_base/declare",
	"dojo/_base/event",
	"dojo/_base/html",
	"dojo/_base/sniff",
	"dojo/_base/window"
],function(dojo){
	return dojo.declare(
		"dojox.mdnd.Moveable",
		null,
	{
		// summary:
		//		Allow end-users to track a DOM node into the web page
	
		// handle: DOMNode
		//		The node on which the user clicks to drag the main node.
		handle: null,
		
		// skip: Boolean
		// 		A flag to control a drag action if a form element has been focused.
		//		If true, the drag action is not executed.
		skip: true,
	
		// dragDistance: Integer
		//		The user clicks on the handle, but the drag action will really begin
		//		if he tracks the main node to more than 3 pixels.
		dragDistance: 3,
		
		constructor: function(/*Object*/params, /*DOMNode*/node){
			// summary:
			// 		Configure parameters and listen to mousedown events from handle
			//		node.
			// params:
			//		Hash of parameters
			// node:
			//		The draggable node
	
			//console.log("dojox.mdnd.Moveable ::: constructor");
			this.node = dojo.byId(node);
			
			this.d = this.node.ownerDocument;
			
			if(!params){ params = {}; }
			this.handle = params.handle ? dojo.byId(params.handle) : null;
			if(!this.handle){ this.handle = this.node; }
			this.skip = params.skip;
			this.events = [
				dojo.connect(this.handle, "onmousedown", this, "onMouseDown")
			];
			if(dojox.mdnd.autoScroll){
				this.autoScroll = dojox.mdnd.autoScroll;
			}
			
		},
		
		isFormElement: function(/*DOMEvent*/ e){
			// summary:
			//		identify the type of target node associated with a DOM event.
			// e:
			//		a DOM event
			// returns:
			//		if true, the target is one of those specific nodes.
	
			//console.log("dojox.mdnd.Moveable ::: isFormElement");
			var t = e.target;
			if(t.nodeType == 3 /*TEXT_NODE*/){
				t = t.parentNode;
			}
			return " a button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0;	// Boolean
		},
		
		onMouseDown: function(/*DOMEvent*/e){
			// summary:
			//		Occurs when the user clicks on the handle node.
			//		Skip the drag action if a specific node is targeted.
			//		Listens to mouseup and mousemove events on to the HTML document.
			// e:
			//		a DOM event
			// tags:
			//		callback
	
			//console.log("dojox.mdnd.Moveable ::: onMouseDown");
			if(this._isDragging){ return;}
			var isLeftButton = (e.which || e.button) == 1;
			if(!isLeftButton){
				return;
			}
			if(this.skip && this.isFormElement(e)){ return; }
			if(this.autoScroll){
				this.autoScroll.setAutoScrollNode(this.node);
				this.autoScroll.setAutoScrollMaxPage();
			}
			this.events.push(dojo.connect(this.d, "onmouseup", this, "onMouseUp"));
			this.events.push(dojo.connect(this.d, "onmousemove", this, "onFirstMove"));
			this._selectStart = dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent);
			this._firstX = e.clientX;
			this._firstY = e.clientY;
			dojo.stopEvent(e);
		},
		
		onFirstMove: function(/*DOMEvent*/e){
			// summary:
			//		Occurs when the user moves the mouse after clicking on the
			//		handle.
			//		Determinate when the drag action will have to begin (see
			//		dragDistance).
			// e:
			//		A DOM event
			// tags:
			//		callback
	
			//console.log("dojox.mdnd.Moveable ::: onFirstMove");
			dojo.stopEvent(e);
			var d = (this._firstX - e.clientX) * (this._firstX - e.clientX)
					+ (this._firstY - e.clientY) * (this._firstY - e.clientY);
			if(d > this.dragDistance * this.dragDistance){
				this._isDragging = true;
				dojo.disconnect(this.events.pop());
				dojo.style(this.node, "width", dojo.contentBox(this.node).w + "px");
				this.initOffsetDrag(e);
				this.events.push(dojo.connect(this.d, "onmousemove", this, "onMove"));
			}
		},
		
		initOffsetDrag: function(/*DOMEvent*/e){
			// summary:
			//		Initialize the gap between main node coordinates and the clicked point.
			//		Call the onDragStart method.
			// e:
			//		A DOM event
	
			//console.log("dojox.mdnd.Moveable ::: initOffsetDrag");
			this.offsetDrag = { 'l': e.pageX, 't': e.pageY };
			var s = this.node.style;
			var position = dojo.position(this.node, true);
			/*if(s.position == "relative" || s.position == ""){
				s.position = "absolute"; // enforcing the absolute mode
			}*/
			this.offsetDrag.l = position.x - this.offsetDrag.l;
			this.offsetDrag.t = position.y - this.offsetDrag.t;
			var coords = {
				'x': position.x,
				'y': position.y
			};
			this.size = {
				'w': position.w,
				'h': position.h
			};
			// method to catch
			this.onDragStart(this.node, coords, this.size);
		},
		
		onMove: function(/*DOMEvent*/e){
			// summary:
			//		Occurs when the user moves the mouse.
			//		Calls the onDrag method.
			// e:
			//		a DOM event
			// tags:
			//		callback
	
			//console.log("dojox.mdnd.Moveable ::: onMove");
			dojo.stopEvent(e);
			// hack to avoid too many calls to onMove in IE8 causing sometimes slowness
			if(dojo.isIE == 8 && new Date() - this.date < 20){
				return;
			}
			if(this.autoScroll){
				this.autoScroll.checkAutoScroll(e);
			}
			var coords = {
				'x': this.offsetDrag.l + e.pageX,
				'y': this.offsetDrag.t + e.pageY
			};
			var s = this.node.style;
			s.left = coords.x + "px";
			s.top = coords.y + "px";
			
			// method to catch
			this.onDrag(this.node, coords, this.size, {'x':e.pageX, 'y':e.pageY});
			if(dojo.isIE == 8){
				this.date = new Date();
			}
		},
		
		onMouseUp: function(/*DOMEvent*/e){
			// summary:
			//		Occurs when the user releases the mouse
			//		Calls the onDragEnd method.
			// e:
			//		a DOM event
	
			if (this._isDragging){
				dojo.stopEvent(e);
				this._isDragging = false;
				if(this.autoScroll){
					this.autoScroll.stopAutoScroll();
				}
				delete this.onMove;
				this.onDragEnd(this.node);
				this.node.focus();
			}
			dojo.disconnect(this.events.pop());
			dojo.disconnect(this.events.pop());
		},
		
		onDragStart: function(/*DOMNode*/node, /*Object*/coords, /*Object*/size){
			// summary:
			//		Stub function.
			//		Notes : border box model
			// node:
			//		a DOM node
			//	coords:
			//		absolute position of the main node
			// size:
			//		an object encapsulating width an height values
			// tags:
			//		callback
	
		},
		
		onDragEnd: function(/*DOMNode*/node){
			// summary:
			//		Stub function
			//		Notes : Coordinates don't contain margins
			// node:
			//		a DOM node
			// tags:
			//		callback
	
		},
		
		onDrag: function(/*DOMNode*/node, /*Object*/coords, /*Object*/size, /*Object*/mousePosition){
			// summary:
			//		Stub function.
			//		Notes : border box model for size value, margin box model for coordinates
			// node:
			//		a DOM node
			// coords:
			//		position of the main node (equals to css left/top properties)
			// size:
			//		an object encapsulating width and height values
			// mousePosition:
			//		coordiantes of mouse
			// tags:
			//		callback
	
		},
	
		destroy: function(){
			// summary:
			//		Delecte associated events
	
			// console.log("dojox.mdnd.Moveable ::: destroy");
			dojo.forEach(this.events, dojo.disconnect);
			this.events = this.node = null;
		}
	});
});