]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/dnd/Source.js.uncompressed.js
1 define("dojo/dnd/Source", ["../main", "./Selector", "./Manager"], function(dojo
, Selector
, Manager
) {
8 Selector = dojo.dnd.Selector;
13 "Horizontal"- if this is the horizontal container
16 "Moved" - this source is being moved
17 "Copied" - this source is being copied
20 "Disabled" - the target cannot accept an avatar
22 "" - item is not selected
23 "Before" - insert point is before the anchor
24 "After" - insert point is after the anchor
28 dojo.dnd.__SourceArgs = function(){
30 // a dict of parameters for DnD Source configuration. Note that any
31 // property on Source elements may be configured, but this is the
34 // can be used as a DnD source. Defaults to true.
36 // list of accepted types (text strings) for a target; defaults to
39 // if true refreshes the node list on every operation; false by default
41 // copy items, if true, use a state of Ctrl key otherwise,
42 // see selfCopy and selfAccept for more details
44 // the move delay in pixels before detecting a drag; 0 by default
45 // horizontal: Boolean?
46 // a horizontal container, if true, vertical otherwise or when omitted
48 // copy items by default when dropping on itself,
49 // false by default, works only if copyOnly is true
50 // selfAccept: Boolean?
51 // accept its own items when copyOnly is true,
52 // true by default, works only if copyOnly is true
53 // withHandles: Boolean?
54 // allows dragging only by handles, false by default
55 // generateText: Boolean?
56 // generate text node for drag and drop, true by default
57 this.isSource = isSource;
59 this.autoSync = autoSync;
60 this.copyOnly = copyOnly;
62 this.horizontal = horizontal;
63 this.selfCopy = selfCopy;
64 this.selfAccept = selfAccept;
65 this.withHandles = withHandles;
66 this.generateText = true;
70 // For back-compat, remove in 2.0.
72 dojo
.ready(0, function(){
73 var requires
= ["dojo/dnd/AutoSource", "dojo/dnd/Target"];
74 require(requires
); // use indirection so modules not rolled into a build
78 return dojo
.declare("dojo.dnd.Source", Selector
, {
80 // a Source object, which can be used as a DnD source, or a DnD target
82 // object attributes (for markup)
95 constructor: function(/*DOMNode|String*/node
, /*dojo.dnd.__SourceArgs?*/params
){
97 // a constructor of the Source
99 // node or node's id to build the source on
101 // any property of this class may be configured via the params
102 // object which is mixed-in to the `dojo.dnd.Source` instance
103 dojo
.mixin(this, dojo
.mixin({}, params
));
104 var type
= this.accept
;
107 for(var i
= 0; i
< type
.length
; ++i
){
108 this.accept
[type
[i
]] = 1;
111 // class-specific variables
112 this.isDragging
= false;
113 this.mouseDown
= false;
114 this.targetAnchor
= null;
115 this.targetBox
= null;
120 this.sourceState
= "";
122 dojo
.addClass(this.node
, "dojoDndSource");
124 this.targetState
= "";
126 dojo
.addClass(this.node
, "dojoDndTarget");
129 dojo
.addClass(this.node
, "dojoDndHorizontal");
133 dojo
.subscribe("/dnd/source/over", this, "onDndSourceOver"),
134 dojo
.subscribe("/dnd/start", this, "onDndStart"),
135 dojo
.subscribe("/dnd/drop", this, "onDndDrop"),
136 dojo
.subscribe("/dnd/cancel", this, "onDndCancel")
141 checkAcceptance: function(source
, nodes
){
143 // checks if the target can accept nodes from this source
145 // the source which provides items
147 // the list of transferred items
149 return !this.copyOnly
|| this.selfAccept
;
151 for(var i
= 0; i
< nodes
.length
; ++i
){
152 var type
= source
.getItem(nodes
[i
].id
).type
;
153 // type instanceof Array
155 for(var j
= 0; j
< type
.length
; ++j
){
156 if(type
[j
] in this.accept
){
162 return false; // Boolean
165 return true; // Boolean
167 copyState: function(keyPressed
, self
){
169 // Returns true if we need to copy items, false to move.
170 // It is separated to be overwritten dynamically, if needed.
171 // keyPressed: Boolean
172 // the "copy" key was pressed
174 // optional flag that means that we are about to drop on itself
176 if(keyPressed
){ return true; }
177 if(arguments
.length
< 2){
178 self
= this == Manager
.manager().target
;
182 return this.selfCopy
;
185 return this.copyOnly
;
187 return false; // Boolean
191 // prepares the object to be garbage-collected
192 dojo
.dnd
.Source
.superclass
.destroy
.call(this);
193 dojo
.forEach(this.topics
, dojo
.unsubscribe
);
194 this.targetAnchor
= null;
197 // mouse event processors
198 onMouseMove: function(e
){
200 // event processor for onmousemove
203 if(this.isDragging
&& this.targetState
== "Disabled"){ return; }
204 dojo
.dnd
.Source
.superclass
.onMouseMove
.call(this, e
);
205 var m
= Manager
.manager();
206 if(!this.isDragging
){
207 if(this.mouseDown
&& this.isSource
&&
208 (Math
.abs(e
.pageX
- this._lastX
) > this.delay
|| Math
.abs(e
.pageY
- this._lastY
) > this.delay
)){
209 var nodes
= this.getSelectedNodes();
211 m
.startDrag(this, nodes
, this.copyState(dojo
.isCopyKey(e
), true));
216 // calculate before/after
219 if(!this.targetBox
|| this.targetAnchor
!= this.current
){
220 this.targetBox
= dojo
.position(this.current
, true);
223 before
= (e
.pageX
- this.targetBox
.x
) < (this.targetBox
.w
/ 2);
225 before
= (e
.pageY
- this.targetBox
.y
) < (this.targetBox
.h
/ 2);
228 if(this.current
!= this.targetAnchor
|| before
!= this.before
){
229 this._markTargetAnchor(before
);
230 m
.canDrop(!this.current
|| m
.source
!= this || !(this.current
.id
in this.selection
));
234 onMouseDown: function(e
){
236 // event processor for onmousedown
239 if(!this.mouseDown
&& this._legalMouseDown(e
) && (!this.skipForm
|| !dojo
.dnd
.isFormElement(e
))){
240 this.mouseDown
= true;
241 this._lastX
= e
.pageX
;
242 this._lastY
= e
.pageY
;
243 dojo
.dnd
.Source
.superclass
.onMouseDown
.call(this, e
);
246 onMouseUp: function(e
){
248 // event processor for onmouseup
252 this.mouseDown
= false;
253 dojo
.dnd
.Source
.superclass
.onMouseUp
.call(this, e
);
257 // topic event processors
258 onDndSourceOver: function(source
){
260 // topic event processor for /dnd/source/over, called when detected a current source
262 // the source which has the mouse over it
264 this.mouseDown
= false;
265 if(this.targetAnchor
){
266 this._unmarkTargetAnchor();
268 }else if(this.isDragging
){
269 var m
= Manager
.manager();
270 m
.canDrop(this.targetState
!= "Disabled" && (!this.current
|| m
.source
!= this || !(this.current
.id
in this.selection
)));
273 onDndStart: function(source
, nodes
, copy
){
275 // topic event processor for /dnd/start, called to initiate the DnD operation
277 // the source which provides items
279 // the list of transferred items
281 // copy items, if true, move items otherwise
282 if(this.autoSync
){ this.sync(); }
284 this._changeState("Source", this == source
? (copy
? "Copied" : "Moved") : "");
286 var accepted
= this.accept
&& this.checkAcceptance(source
, nodes
);
287 this._changeState("Target", accepted
? "" : "Disabled");
289 Manager
.manager().overSource(this);
291 this.isDragging
= true;
293 onDndDrop: function(source
, nodes
, copy
, target
){
295 // topic event processor for /dnd/drop, called to finish the DnD operation
297 // the source which provides items
299 // the list of transferred items
301 // copy items, if true, move items otherwise
303 // the target which accepts items
305 // this one is for us => move nodes!
306 this.onDrop(source
, nodes
, copy
);
310 onDndCancel: function(){
312 // topic event processor for /dnd/cancel, called to cancel the DnD operation
313 if(this.targetAnchor
){
314 this._unmarkTargetAnchor();
315 this.targetAnchor
= null;
318 this.isDragging
= false;
319 this.mouseDown
= false;
320 this._changeState("Source", "");
321 this._changeState("Target", "");
325 onDrop: function(source
, nodes
, copy
){
327 // called only on the current target, when drop is performed
329 // the source which provides items
331 // the list of transferred items
333 // copy items, if true, move items otherwise
336 this.onDropExternal(source
, nodes
, copy
);
338 this.onDropInternal(nodes
, copy
);
341 onDropExternal: function(source
, nodes
, copy
){
343 // called only on the current target, when drop is performed
344 // from an external source
346 // the source which provides items
348 // the list of transferred items
350 // copy items, if true, move items otherwise
352 var oldCreator
= this._normalizedCreator
;
353 // transferring nodes from the source to the target
355 // use defined creator
356 this._normalizedCreator = function(node
, hint
){
357 return oldCreator
.call(this, source
.getItem(node
.id
).data
, hint
);
360 // we have no creator defined => move/clone nodes
363 this._normalizedCreator = function(node
, hint
){
364 var t
= source
.getItem(node
.id
);
365 var n
= node
.cloneNode(true);
366 n
.id
= dojo
.dnd
.getUniqueId();
367 return {node
: n
, data
: t
.data
, type
: t
.type
};
371 this._normalizedCreator = function(node
, hint
){
372 var t
= source
.getItem(node
.id
);
373 source
.delItem(node
.id
);
374 return {node
: node
, data
: t
.data
, type
: t
.type
};
379 if(!copy
&& !this.creator
){
382 this.insertNodes(true, nodes
, this.before
, this.current
);
383 if(!copy
&& this.creator
){
384 source
.deleteSelectedNodes();
386 this._normalizedCreator
= oldCreator
;
388 onDropInternal: function(nodes
, copy
){
390 // called only on the current target, when drop is performed
391 // from the same target/source
393 // the list of transferred items
395 // copy items, if true, move items otherwise
397 var oldCreator
= this._normalizedCreator
;
398 // transferring nodes within the single source
399 if(this.current
&& this.current
.id
in this.selection
){
405 // create new copies of data items
406 this._normalizedCreator = function(node
, hint
){
407 return oldCreator
.call(this, this.getItem(node
.id
).data
, hint
);
411 this._normalizedCreator = function(node
, hint
){
412 var t
= this.getItem(node
.id
);
413 var n
= node
.cloneNode(true);
414 n
.id
= dojo
.dnd
.getUniqueId();
415 return {node
: n
, data
: t
.data
, type
: t
.type
};
424 this._normalizedCreator = function(node
, hint
){
425 var t
= this.getItem(node
.id
);
426 return {node
: node
, data
: t
.data
, type
: t
.type
};
429 this._removeSelection();
430 this.insertNodes(true, nodes
, this.before
, this.current
);
431 this._normalizedCreator
= oldCreator
;
433 onDraggingOver: function(){
435 // called during the active DnD operation, when items
436 // are dragged over this target, and it is not disabled
438 onDraggingOut: function(){
440 // called during the active DnD operation, when items
441 // are dragged away from this target, and it is not disabled
445 onOverEvent: function(){
447 // this function is called once, when mouse is over our container
448 dojo
.dnd
.Source
.superclass
.onOverEvent
.call(this);
449 Manager
.manager().overSource(this);
450 if(this.isDragging
&& this.targetState
!= "Disabled"){
451 this.onDraggingOver();
454 onOutEvent: function(){
456 // this function is called once, when mouse is out of our container
457 dojo
.dnd
.Source
.superclass
.onOutEvent
.call(this);
458 Manager
.manager().outSource(this);
459 if(this.isDragging
&& this.targetState
!= "Disabled"){
460 this.onDraggingOut();
463 _markTargetAnchor: function(before
){
465 // assigns a class to the current target anchor based on "before" status
467 // insert before, if true, after otherwise
468 if(this.current
== this.targetAnchor
&& this.before
== before
){ return; }
469 if(this.targetAnchor
){
470 this._removeItemClass(this.targetAnchor
, this.before
? "Before" : "After");
472 this.targetAnchor
= this.current
;
473 this.targetBox
= null;
474 this.before
= before
;
475 if(this.targetAnchor
){
476 this._addItemClass(this.targetAnchor
, this.before
? "Before" : "After");
479 _unmarkTargetAnchor: function(){
481 // removes a class of the current target anchor based on "before" status
482 if(!this.targetAnchor
){ return; }
483 this._removeItemClass(this.targetAnchor
, this.before
? "Before" : "After");
484 this.targetAnchor
= null;
485 this.targetBox
= null;
488 _markDndStatus: function(copy
){
490 // changes source's state based on "copy" status
491 this._changeState("Source", copy
? "Copied" : "Moved");
493 _legalMouseDown: function(e
){
495 // checks if user clicked on "approved" items
499 // accept only the left mouse button
500 if(!dojo
.mouseButtons
.isLeft(e
)){ return false; }
502 if(!this.withHandles
){ return true; }
505 for(var node
= e
.target
; node
&& node
!== this.node
; node
= node
.parentNode
){
506 if(dojo
.hasClass(node
, "dojoDndHandle")){ return true; }
507 if(dojo
.hasClass(node
, "dojoDndItem") || dojo
.hasClass(node
, "dojoDndIgnore")){ break; }
509 return false; // Boolean