Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dijit._tree.dndSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dijit._tree.dndSource"] = true;
3
dojo.provide("dijit._tree.dndSource");
4
 
5
dojo.require("dijit._tree.dndSelector");
6
dojo.require("dojo.dnd.Manager");
7
 
8
dojo.declare("dijit._tree.dndSource", dijit._tree.dndSelector, {
9
	// summary: a Source object, which can be used as a DnD source, or a DnD target
10
 
11
	// object attributes (for markup)
12
	isSource: true,
13
	copyOnly: false,
14
	skipForm: false,
15
	accept: ["text"],
16
 
17
	constructor: function(node, params){
18
		// summary: a constructor of the Source
19
		// node: Node: node or node's id to build the source on
20
		// params: Object: a dict of parameters, recognized parameters are:
21
		//	isSource: Boolean: can be used as a DnD source, if true; assumed to be "true" if omitted
22
		//	accept: Array: list of accepted types (text strings) for a target; assumed to be ["text"] if omitted
23
		//	horizontal: Boolean: a horizontal container, if true, vertical otherwise or when omitted
24
		//	copyOnly: Boolean: always copy items, if true, use a state of Ctrl key otherwise
25
		//	skipForm: Boolean: don't start the drag operation, if clicked on form elements
26
		//	the rest of parameters are passed to the selector
27
		if(!params){ params = {}; }
28
		dojo.mixin(this, params);
29
		this.isSource = typeof params.isSource == "undefined" ? true : params.isSource;
30
		var type = params.accept instanceof Array ? params.accept : ["text"];
31
		this.accept = null;
32
		if(type.length){
33
			this.accept = {};
34
			for(var i = 0; i < type.length; ++i){
35
				this.accept[type[i]] = 1;
36
			}
37
		}
38
 
39
		// class-specific variables
40
		this.isDragging = false;
41
		this.mouseDown = false;
42
		this.targetAnchor = null;
43
		this.targetBox = null;
44
		this.before = true;
45
 
46
		// states
47
		this.sourceState  = "";
48
		if(this.isSource){
49
			dojo.addClass(this.node, "dojoDndSource");
50
		}
51
		this.targetState  = "";
52
		if(this.accept){
53
			dojo.addClass(this.node, "dojoDndTarget");
54
		}
55
		if(this.horizontal){
56
			dojo.addClass(this.node, "dojoDndHorizontal");
57
		}
58
		// set up events
59
		this.topics = [
60
			dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),
61
			dojo.subscribe("/dnd/start",  this, "onDndStart"),
62
			dojo.subscribe("/dnd/drop",   this, "onDndDrop"),
63
			dojo.subscribe("/dnd/cancel", this, "onDndCancel")
64
		];
65
	},
66
 
67
	startup: function(){
68
	},
69
 
70
	// methods
71
	checkAcceptance: function(source, nodes){
72
		// summary: checks, if the target can accept nodes from this source
73
		// source: Object: the source which provides items
74
		// nodes: Array: the list of transferred items
75
		return true;	// Boolean
76
	},
77
	copyState: function(keyPressed){
78
		// summary: Returns true, if we need to copy items, false to move.
79
		//		It is separated to be overwritten dynamically, if needed.
80
		// keyPressed: Boolean: the "copy" was pressed
81
		return this.copyOnly || keyPressed;	// Boolean
82
	},
83
	destroy: function(){
84
		// summary: prepares the object to be garbage-collected
85
		this.inherited("destroy",arguments);
86
		dojo.forEach(this.topics, dojo.unsubscribe);
87
		this.targetAnchor = null;
88
	},
89
 
90
	// markup methods
91
	markupFactory: function(params, node){
92
		params._skipStartup = true;
93
		return new dijit._tree.dndSource(node, params);
94
	},
95
 
96
	// mouse event processors
97
	onMouseMove: function(e){
98
		// summary: event processor for onmousemove
99
		// e: Event: mouse event
100
		if(this.isDragging && this.targetState == "Disabled"){ return; }
101
		this.inherited("onMouseMove", arguments);
102
		var m = dojo.dnd.manager();
103
		if(this.isDragging){
104
			// calculate before/after
105
 
106
			if (this.allowBetween){ // not implemented yet for tree since it has no concept of order
107
				var before = false;
108
				if(this.current){
109
					if(!this.targetBox || this.targetAnchor != this.current){
110
						this.targetBox = {
111
							xy: dojo.coords(this.current, true),
112
							w: this.current.offsetWidth,
113
							h: this.current.offsetHeight
114
						};
115
					}
116
					if(this.horizontal){
117
						before = (e.pageX - this.targetBox.xy.x) < (this.targetBox.w / 2);
118
					}else{
119
						before = (e.pageY - this.targetBox.xy.y) < (this.targetBox.h / 2);
120
					}
121
				}
122
				if(this.current != this.targetAnchor || before != this.before){
123
					this._markTargetAnchor(before);
124
					m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
125
				}
126
			}
127
		}else{
128
			if(this.mouseDown && this.isSource){
129
				var n = this.getSelectedNodes();
130
				var nodes=[];
131
				for (var i in n){
132
					nodes.push(n[i]);
133
				}
134
				if(nodes.length){
135
					m.startDrag(this, nodes, this.copyState(dojo.dnd.getCopyKeyState(e)));
136
				}
137
			}
138
		}
139
	},
140
 
141
	onMouseDown: function(e){
142
		// summary: event processor for onmousedown
143
		// e: Event: mouse event
144
		this.mouseDown = true;
145
		this.mouseButton = e.button;
146
		this.inherited("onMouseDown",arguments);
147
	},
148
 
149
	onMouseUp: function(e){
150
		// summary: event processor for onmouseup
151
		// e: Event: mouse event
152
		if(this.mouseDown){
153
			this.mouseDown = false;
154
			this.inherited("onMouseUp",arguments);
155
		}
156
	},
157
 
158
	onMouseOver: function(e){
159
		// summary: event processor for onmouseover
160
		// e: Event: mouse event
161
		var n = e.relatedTarget;
162
		while(n){
163
			if(n == this.node){ break; }
164
			try{
165
				n = n.parentNode;
166
			}catch(x){
167
				n = null;
168
			}
169
		}
170
		if(!n){
171
			this._changeState("Container", "Over");
172
			this.onOverEvent();
173
		}
174
		n = this._getChildByEvent(e);
175
		if(this.current == n){ return; }
176
		if(this.current){ this._removeItemClass(this.current, "Over"); }
177
		if(n){
178
			this._addItemClass(n, "Over");
179
			if(this.isDragging){
180
				var m = dojo.dnd.manager();
181
				if(this.checkItemAcceptance(n,m.source)){
182
					m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
183
				}else{
184
					m.canDrop(false);
185
				}
186
			}
187
		}else{
188
			if(this.isDragging){
189
				var m = dojo.dnd.manager();
190
				if (m.source && this.checkAcceptance(m.source,m.source.getSelectedNodes())){
191
					m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
192
				}else{
193
					m.canDrop(false);
194
				}
195
			}
196
		}
197
		this.current = n;
198
	},
199
 
200
	checkItemAcceptance: function(node, source){
201
		// summary: stub funciton to be overridden if one wants to check for the ability to drop at the node/item level
202
			return true;
203
	},
204
 
205
	// topic event processors
206
	onDndSourceOver: function(source){
207
		// summary: topic event processor for /dnd/source/over, called when detected a current source
208
		// source: Object: the source which has the mouse over it
209
		if(this != source){
210
			this.mouseDown = false;
211
			if(this.targetAnchor){
212
				this._unmarkTargetAnchor();
213
			}
214
		}else if(this.isDragging){
215
			var m = dojo.dnd.manager();
216
			m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
217
		}
218
	},
219
	onDndStart: function(source, nodes, copy){
220
		// summary: topic event processor for /dnd/start, called to initiate the DnD operation
221
		// source: Object: the source which provides items
222
		// nodes: Array: the list of transferred items
223
		// copy: Boolean: copy items, if true, move items otherwise
224
 
225
		if(this.isSource){
226
			this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
227
		}
228
		var accepted = this.checkAcceptance(source, nodes);
229
 
230
		this._changeState("Target", accepted ? "" : "Disabled");
231
 
232
		if(accepted){
233
			dojo.dnd.manager().overSource(this);
234
		}
235
 
236
		this.isDragging = true;
237
	},
238
 
239
	itemCreator: function(nodes){
240
		var items = []
241
 
242
		for(var i=0;i<nodes.length;i++){
243
			items.push({
244
				"name":nodes[i].textContent,
245
				"id": nodes[i].id
246
			});
247
		}
248
 
249
		return items;
250
	},
251
 
252
	onDndDrop: function(source, nodes, copy){
253
		// summary: topic event processor for /dnd/drop, called to finish the DnD operation
254
		// source: Object: the source which provides items
255
		// nodes: Array: the list of transferred items
256
		// copy: Boolean: copy items, if true, move items otherwise
257
 
258
		if(this.containerState == "Over"){
259
			this.isDragging = false;
260
			var target = this.current;
261
			var items = this.itemCreator(nodes, target);
262
			if(!target || target == this.tree.domNode){
263
				for(var i = 0; i < items.length; i++){
264
					this.tree.store.newItem(items[i], null);
265
				}
266
			}else{
267
				for(var i = 0; i < items.length; i++){
268
					pInfo = {parent: dijit.getEnclosingWidget(target).item, attribute: "children"};
269
					var newItem = this.tree.store.newItem(items[i], pInfo);
270
					console.log("newItem:", newItem);
271
				}
272
			}
273
		}
274
		this.onDndCancel();
275
	},
276
	onDndCancel: function(){
277
		// summary: topic event processor for /dnd/cancel, called to cancel the DnD operation
278
		if(this.targetAnchor){
279
			this._unmarkTargetAnchor();
280
			this.targetAnchor = null;
281
		}
282
		this.before = true;
283
		this.isDragging = false;
284
		this.mouseDown = false;
285
		delete this.mouseButton;
286
		this._changeState("Source", "");
287
		this._changeState("Target", "");
288
	},
289
 
290
	// utilities
291
 
292
	onOverEvent: function(){
293
		// summary: this function is called once, when mouse is over our container
294
		this.inherited("onOverEvent",arguments);
295
		dojo.dnd.manager().overSource(this);
296
	},
297
	onOutEvent: function(){
298
		// summary: this function is called once, when mouse is out of our container
299
		this.inherited("onOutEvent",arguments);
300
		dojo.dnd.manager().outSource(this);
301
	},
302
	_markTargetAnchor: function(before){
303
		// summary: assigns a class to the current target anchor based on "before" status
304
		// before: Boolean: insert before, if true, after otherwise
305
		if(this.current == this.targetAnchor && this.before == before){ return; }
306
		if(this.targetAnchor){
307
			this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
308
		}
309
		this.targetAnchor = this.current;
310
		this.targetBox = null;
311
		this.before = before;
312
		if(this.targetAnchor){
313
			this._addItemClass(this.targetAnchor, this.before ? "Before" : "After");
314
		}
315
	},
316
	_unmarkTargetAnchor: function(){
317
		// summary: removes a class of the current target anchor based on "before" status
318
		if(!this.targetAnchor){ return; }
319
		this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
320
		this.targetAnchor = null;
321
		this.targetBox = null;
322
		this.before = true;
323
	},
324
	_markDndStatus: function(copy){
325
		// summary: changes source's state based on "copy" status
326
		this._changeState("Source", copy ? "Copied" : "Moved");
327
	}
328
});
329
 
330
dojo.declare("dijit._tree.dndTarget", dijit._tree.dndSource, {
331
	// summary: a Target object, which can be used as a DnD target
332
 
333
	constructor: function(node, params){
334
		// summary: a constructor of the Target --- see the Source constructor for details
335
		this.isSource = false;
336
		dojo.removeClass(this.node, "dojoDndSource");
337
	},
338
 
339
	// markup methods
340
	markupFactory: function(params, node){
341
		params._skipStartup = true;
342
		return new dijit._tree.dndTarget(node, params);
343
	}
344
});
345
 
346
}