3
Copyright 2012 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('sortable', function(Y) {
11
* The class allows you to create a Drag & Drop reordered list.
15
* The class allows you to create a Drag & Drop reordered list.
22
var Sortable = function(o) {
23
Sortable.superclass.constructor.apply(this, arguments);
25
CURRENT_NODE = 'currentNode',
26
OPACITY_NODE = 'opacityNode',
31
PARENT_NODE = 'parentNode',
36
Y.extend(Sortable, Y.Base, {
40
* @description A reference to the DD.Delegate instance.
43
initializer: function() {
44
var id = 'sortable-' + Y.guid(), c,
46
container: this.get(CONT),
47
nodes: this.get(NODES),
49
invalid: this.get('invalid'),
55
if (this.get('handles')) {
56
delConfig.handles = this.get('handles');
58
del = new Y.DD.Delegate(delConfig);
62
del.dd.plug(Y.Plugin.DDProxy, {
70
groups: del.dd.get('groups')
71
}).on('drop:over', Y.bind(this._onDropOver, this));
74
'drag:start': Y.bind(this._onDragStart, this),
75
'drag:end': Y.bind(this._onDragEnd, this),
76
'drag:over': Y.bind(this._onDragOver, this),
77
'drag:drag': Y.bind(this._onDrag, this)
85
_onDrag: function(e) {
86
if (e.pageY < this._y) {
88
} else if (e.pageY > this._y) {
97
* @param Event e The Event Object
98
* @description Handles the DropOver event to append a drop node to an empty target
100
_onDropOver: function(e) {
101
if (!e.drop.get(NODE).test(this.get(NODES))) {
102
var nodes = e.drop.get(NODE).all(this.get(NODES));
103
if (nodes.size() === 0) {
104
e.drop.get(NODE).append(e.drag.get(NODE));
110
* @method _onDragOver
111
* @param Event e The Event Object
112
* @description Handles the DragOver event that moves the object in the list or to another list.
114
_onDragOver: function(e) {
115
if (!e.drop.get(NODE).test(this.get(NODES))) {
118
if (e.drag.get(NODE) == e.drop.get(NODE)) {
121
// is drop a child of drag?
122
if (e.drag.get(NODE).contains(e.drop.get(NODE))) {
125
var same = false, dir, oldNode, newNode, dropsort, dropNode,
126
moveType = this.get('moveType').toLowerCase();
128
if (e.drag.get(NODE).get(PARENT_NODE).contains(e.drop.get(NODE))) {
131
if (same && moveType == 'move') {
136
dir = ((this._up) ? 'before' : 'after');
137
dropNode = e.drop.get(NODE);
138
if (Y.Sortable._test(dropNode, this.get(CONT))) {
139
dropNode.append(e.drag.get(NODE));
141
dropNode.insert(e.drag.get(NODE), dir);
145
Y.DD.DDM.swapNode(e.drag, e.drop);
149
dropsort = Y.Sortable.getSortable(e.drop.get(NODE).get(PARENT_NODE));
155
Y.DD.DDM.getDrop(e.drag.get(NODE)).addToGroup(dropsort.get(ID));
159
Y.DD.DDM.swapNode(e.drag, e.drop);
161
if (this.get('moveType') == 'copy') {
163
oldNode = e.drag.get(NODE);
164
newNode = oldNode.cloneNode(true);
167
e.drag.set(NODE, newNode);
168
dropsort.delegate.createDrop(newNode, [dropsort.get(ID)]);
174
e.drop.get(NODE).insert(e.drag.get(NODE), 'before');
179
this.fire(moveType, { same: same, drag: e.drag, drop: e.drop });
180
this.fire('moved', { same: same, drag: e.drag, drop: e.drop });
184
* @method _onDragStart
185
* @param Event e The Event Object
186
* @description Handles the DragStart event and initializes some settings.
188
_onDragStart: function(e) {
189
this.delegate.get('lastNode').setStyle(ZINDEX, '');
190
this.delegate.get(this.get(OPACITY_NODE)).setStyle(OPACITY, this.get(OPACITY));
191
this.delegate.get(CURRENT_NODE).setStyle(ZINDEX, '999');
196
* @param Event e The Event Object
197
* @description Handles the DragEnd event that cleans up the settings in the drag:start event.
199
_onDragEnd: function(e) {
200
this.delegate.get(this.get(OPACITY_NODE)).setStyle(OPACITY, 1);
201
this.delegate.get(CURRENT_NODE).setStyles({
209
* @param Class cls The class to plug
210
* @param Object config The class config
211
* @description Passthrough to the DD.Delegate.ddplug method
214
plug: function(cls, config) {
215
//I don't like this.. Not at all, need to discuss with the team
216
if (cls && cls.NAME.substring(0, 4).toLowerCase() === 'sort') {
217
this.constructor.superclass.plug.call(this, cls, config);
219
this.delegate.dd.plug(cls, config);
225
* @description Passthrough to the DD.Delegate syncTargets method.
229
this.delegate.syncTargets();
232
destructor: function() {
233
this.delegate.destroy();
234
Sortable.unreg(this);
238
* @param Sortable sel The Sortable list to join with
239
* @param String type The type of join to do: full, inner, outer, none. Default: full
240
* @description Join this Sortable with another Sortable instance.
242
* <li>full: Exchange nodes with both lists.</li>
243
* <li>inner: Items can go into this list from the joined list.</li>
244
* <li>outer: Items can go out of the joined list into this list.</li>
245
* <li>none: Removes the join.</li>
249
join: function(sel, type) {
250
if (!(sel instanceof Y.Sortable)) {
251
Y.error('Sortable: join needs a Sortable Instance');
257
type = type.toLowerCase();
258
var method = '_join_' + type;
269
* @param Sortable sel The Sortable to remove the join from
270
* @description Removes the join with the passed Sortable.
272
_join_none: function(sel) {
273
this.delegate.dd.removeFromGroup(sel.get(ID));
274
sel.delegate.dd.removeFromGroup(this.get(ID));
279
* @param Sortable sel The Sortable list to join with
280
* @description Joins both of the Sortables together.
282
_join_full: function(sel) {
283
this.delegate.dd.addToGroup(sel.get(ID));
284
sel.delegate.dd.addToGroup(this.get(ID));
288
* @method _join_outer
289
* @param Sortable sel The Sortable list to join with
290
* @description Allows this Sortable to accept items from the passed Sortable.
292
_join_outer: function(sel) {
293
this.delegate.dd.addToGroup(sel.get(ID));
297
* @method _join_inner
298
* @param Sortable sel The Sortable list to join with
299
* @description Allows this Sortable to give items to the passed Sortable.
301
_join_inner: function(sel) {
302
sel.delegate.dd.addToGroup(this.get(ID));
305
* A custom callback to allow a user to extract some sort of id or any other data from the node to use in the "ordering list" and then that data should be returned from the callback.
306
* @method getOrdering
307
* @param Function callback
310
getOrdering: function(callback) {
313
if (!Y.Lang.isFunction(callback)) {
314
callback = function (node) {
319
Y.one(this.get(CONT)).all(this.get(NODES)).each(function(node) {
320
ordering.push(callback(node));
329
* @description Drag handles to pass on to the internal DD.Delegate instance.
336
* @attribute container
337
* @description A selector query to get the container to listen for mousedown events on. All "nodes" should be a child of this container.
345
* @description A selector query to get the children of the "container" to make draggable elements from.
349
value: '.dd-draggable'
353
* @description The opacity to change the proxy item to when dragging.
360
* @attribute opacityNode
361
* @description The node to set opacity on when dragging (dragNode or currentNode). Default: currentNode.
369
* @description The id of this Sortable, used to get a reference to this Sortable list from another list.
376
* @attribute moveType
377
* @description How should an item move to another list: insert, swap, move, copy. Default: insert
385
* @description A selector string to test if a list item is invalid and not sortable
394
* @property _sortables
397
* @description Hash map of all Sortables on the page.
403
* @param {Node} node The node instance to test.
404
* @param {String|Node} test The node instance or selector string to test against.
405
* @description Test a Node or a selector for the container
407
_test: function(node, test) {
408
if (test instanceof Y.Node) {
409
return (test === node);
411
return node.test(test);
416
* @method getSortable
417
* @param {String|Node} node The node instance or selector string to use to find a Sortable instance.
418
* @description Get a Sortable instance back from a node reference or a selector string.
420
getSortable: function(node) {
423
Y.each(Y.Sortable._sortables, function(v) {
424
if (Y.Sortable._test(node, v.get(CONT))) {
433
* @param Sortable s A Sortable instance.
434
* @description Register a Sortable instance with the singleton to allow lookups later.
437
Y.Sortable._sortables.push(s);
442
* @param Sortable s A Sortable instance.
443
* @description Unregister a Sortable instance with the singleton.
446
Y.each(Y.Sortable._sortables, function(v, k) {
448
Y.Sortable._sortables[k] = null;
449
delete Sortable._sortables[k];
455
Y.Sortable = Sortable;
459
* @description A Sortable node was moved with a copy.
460
* @param {Event.Facade} event An Event Facade object
461
* @param {Boolean} event.same Moved to the same list.
462
* @param {DD.Drag} event.drag The drag instance.
463
* @param {DD.Drop} event.drop The drop instance.
464
* @type {Event.Custom}
468
* @description A Sortable node was moved with a move.
469
* @param {Event.Facade} event An Event Facade object with the following specific property added:
470
* @param {Boolean} event.same Moved to the same list.
471
* @param {DD.Drag} event.drag The drag instance.
472
* @param {DD.Drop} event.drop The drop instance.
473
* @type {Event.Custom}
477
* @description A Sortable node was moved with an insert.
478
* @param {Event.Facade} event An Event Facade object with the following specific property added:
479
* @param {Boolean} event.same Moved to the same list.
480
* @param {DD.Drag} event.drag The drag instance.
481
* @param {DD.Drop} event.drop The drop instance.
482
* @type {Event.Custom}
486
* @description A Sortable node was moved with a swap.
487
* @param {Event.Facade} event An Event Facade object with the following specific property added:
488
* @param {Boolean} event.same Moved to the same list.
489
* @param {DD.Drag} event.drag The drag instance.
490
* @param {DD.Drop} event.drop The drop instance.
491
* @type {Event.Custom}
495
* @description A Sortable node was moved.
496
* @param {Event.Facade} event An Event Facade object with the following specific property added:
497
* @param {Boolean} event.same Moved to the same list.
498
* @param {DD.Drag} event.drag The drag instance.
499
* @param {DD.Drop} event.drop The drop instance.
500
* @type {Event.Custom}
505
}, '3.5.0' ,{requires:['dd-delegate', 'dd-drop-plugin', 'dd-proxy']});