2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
8 YUI.add('sortable', function (Y, NAME) {
12 * The class allows you to create a Drag & Drop reordered list.
16 * The class allows you to create a Drag & Drop reordered list.
23 var Sortable = function() {
24 Sortable.superclass.constructor.apply(this, arguments);
26 CURRENT_NODE = 'currentNode',
27 OPACITY_NODE = 'opacityNode',
32 PARENT_NODE = 'parentNode',
37 Y.extend(Sortable, Y.Base, {
41 * @description A reference to the DD.Delegate instance.
47 * @description A reference to the DD.Drop instance
50 initializer: function() {
51 var id = 'sortable-' + Y.guid(),
53 container: this.get(CONT),
54 nodes: this.get(NODES),
56 invalid: this.get('invalid'),
62 if (this.get('handles')) {
63 delConfig.handles = this.get('handles');
65 del = new Y.DD.Delegate(delConfig);
69 del.dd.plug(Y.Plugin.DDProxy, {
74 this.drop = new Y.DD.Drop({
77 groups: del.dd.get('groups')
79 this.drop.on('drop:enter', Y.bind(this._onDropEnter, this));
82 'drag:start': Y.bind(this._onDragStart, this),
83 'drag:end': Y.bind(this._onDragEnd, this),
84 'drag:over': Y.bind(this._onDragOver, this),
85 'drag:drag': Y.bind(this._onDrag, this)
89 Sortable.reg(this, id);
93 _onDrag: function(e) {
94 if (e.pageY < this._y) {
96 } else if (e.pageY > this._y) {
104 * @method _onDropEnter
105 * @param Event e The Event Object
106 * @description Handles the DropEnter event to append a new node to a target.
108 _onDropEnter: function(e) {
109 var dropNode = e.drop.get(NODE),
110 dragNode = e.drag.get(NODE);
112 if (!dropNode.test(this.get(NODES)) &&
113 !dragNode.get(PARENT_NODE).compareTo(dropNode)) {
114 dropNode.append(dragNode);
119 * @method _onDragOver
120 * @param Event e The Event Object
121 * @description Handles the DragOver event that moves the object in the list or to another list.
123 _onDragOver: function(e) {
124 if (!e.drop.get(NODE).test(this.get(NODES))) {
127 if (e.drag.get(NODE) === e.drop.get(NODE)) {
130 // is drop a child of drag?
131 if (e.drag.get(NODE).contains(e.drop.get(NODE))) {
134 var same = false, dir, oldNode, newNode, dropsort, dropNode,
135 moveType = this.get('moveType').toLowerCase();
137 if (e.drag.get(NODE).get(PARENT_NODE).contains(e.drop.get(NODE))) {
140 if (same && moveType === 'move') {
145 dir = ((this._up) ? 'before' : 'after');
146 dropNode = e.drop.get(NODE);
147 if (Y.Sortable._test(dropNode, this.get(CONT))) {
148 dropNode.append(e.drag.get(NODE));
150 dropNode.insert(e.drag.get(NODE), dir);
154 Y.DD.DDM.swapNode(e.drag, e.drop);
158 dropsort = Y.Sortable.getSortable(e.drop.get(NODE).get(PARENT_NODE));
161 Y.log('No delegate parent found', 'error', 'sortable');
165 Y.DD.DDM.getDrop(e.drag.get(NODE)).addToGroup(dropsort.get(ID));
169 Y.DD.DDM.swapNode(e.drag, e.drop);
171 if (this.get('moveType') === 'copy') {
173 oldNode = e.drag.get(NODE);
174 newNode = oldNode.cloneNode(true);
177 e.drag.set(NODE, newNode);
178 dropsort.delegate.createDrop(newNode, [dropsort.get(ID)]);
184 e.drop.get(NODE).insert(e.drag.get(NODE), 'before');
189 this.fire(moveType, { same: same, drag: e.drag, drop: e.drop });
190 this.fire('moved', { same: same, drag: e.drag, drop: e.drop });
194 * @method _onDragStart
195 * @param Event e The Event Object
196 * @description Handles the DragStart event and initializes some settings.
198 _onDragStart: function() {
199 var del = this.delegate,
200 lastNode = del.get('lastNode');
201 if (lastNode && lastNode.getDOMNode()) {
202 lastNode.setStyle(ZINDEX, '');
204 del.get(this.get(OPACITY_NODE)).setStyle(OPACITY, this.get(OPACITY));
205 del.get(CURRENT_NODE).setStyle(ZINDEX, '999');
210 * @param Event e The Event Object
211 * @description Handles the DragEnd event that cleans up the settings in the drag:start event.
213 _onDragEnd: function() {
214 this.delegate.get(this.get(OPACITY_NODE)).setStyle(OPACITY, 1);
215 this.delegate.get(CURRENT_NODE).setStyles({
223 * @param Class cls The class to plug
224 * @param Object config The class config
225 * @description Passthrough to the DD.Delegate.ddplug method
228 plug: function(cls, config) {
229 //I don't like this.. Not at all, need to discuss with the team
230 if (cls && cls.NAME.substring(0, 4).toLowerCase() === 'sort') {
231 this.constructor.superclass.plug.call(this, cls, config);
233 this.delegate.dd.plug(cls, config);
239 * @description Passthrough to the DD.Delegate syncTargets method.
243 this.delegate.syncTargets();
246 destructor: function() {
248 this.delegate.destroy();
249 Sortable.unreg(this, this.get(ID));
253 * @param Sortable sel The Sortable list to join with
254 * @param String type The type of join to do: full, inner, outer, none. Default: full
255 * @description Join this Sortable with another Sortable instance.
257 * <li>full: Exchange nodes with both lists.</li>
258 * <li>inner: Items can go into this list from the joined list.</li>
259 * <li>outer: Items can go out of the joined list into this list.</li>
260 * <li>none: Removes the join.</li>
264 join: function(sel, type) {
265 if (!(sel instanceof Y.Sortable)) {
266 Y.error('Sortable: join needs a Sortable Instance');
272 type = type.toLowerCase();
273 var method = '_join_' + type;
284 * @param Sortable sel The Sortable to remove the join from
285 * @description Removes the join with the passed Sortable.
287 _join_none: function(sel) {
288 this.delegate.dd.removeFromGroup(sel.get(ID));
289 sel.delegate.dd.removeFromGroup(this.get(ID));
294 * @param Sortable sel The Sortable list to join with
295 * @description Joins both of the Sortables together.
297 _join_full: function(sel) {
298 this.delegate.dd.addToGroup(sel.get(ID));
299 sel.delegate.dd.addToGroup(this.get(ID));
303 * @method _join_outer
304 * @param Sortable sel The Sortable list to join with
305 * @description Allows this Sortable to accept items from the passed Sortable.
307 _join_outer: function(sel) {
308 this.delegate.dd.addToGroup(sel.get(ID));
312 * @method _join_inner
313 * @param Sortable sel The Sortable list to join with
314 * @description Allows this Sortable to give items to the passed Sortable.
316 _join_inner: function(sel) {
317 sel.delegate.dd.addToGroup(this.get(ID));
320 * A custom callback to allow a user to extract some sort of id or any other data
321 * from the node to use in the "ordering list" and then that data should be returned from the callback.
322 * @method getOrdering
323 * @param Function callback
326 getOrdering: function(callback) {
329 if (!Y.Lang.isFunction(callback)) {
330 callback = function (node) {
335 Y.one(this.get(CONT)).all(this.get(NODES)).each(function(node) {
336 ordering.push(callback(node));
345 * @description Drag handles to pass on to the internal DD.Delegate instance.
352 * @attribute container
353 * @description A selector query to get the container to listen for mousedown events on. All "nodes" should be a child of this container.
361 * @description A selector query to get the children of the "container" to make draggable elements from.
365 value: '.dd-draggable'
369 * @description The opacity to change the proxy item to when dragging.
376 * @attribute opacityNode
377 * @description The node to set opacity on when dragging (dragNode or currentNode). Default: currentNode.
385 * @description The id of this Sortable, used to get a reference to this Sortable list from another list.
392 * @attribute moveType
393 * @description How should an item move to another list: insert, swap, move, copy. Default: insert
401 * @description A selector string to test if a list item is invalid and not sortable
410 * @property _sortables
413 * @description Hash map of all Sortables on the page.
419 * @param {Node} node The node instance to test.
420 * @param {String|Node} test The node instance or selector string to test against.
421 * @description Test a Node or a selector for the container
423 _test: function(node, test) {
425 if (test instanceof Y.Node) {
426 ret = (test === node);
428 ret = node.test(test);
434 * @method getSortable
435 * @param {String|Node} node The node instance or selector string to use to find a Sortable instance.
436 * @description Get a Sortable instance back from a node reference or a selector string.
438 getSortable: function(node) {
443 if(id && Y.Sortable._sortables[id]) {
444 return Y.Sortable._sortables[id];
446 Y.Object.each(Y.Sortable._sortables, function(v) {
447 if (Y.Sortable._test(node, v.get(CONT))) {
456 * @param Sortable s A Sortable instance.
457 * @param String id (optional) The id of the sortable instance.
458 * @description Register a Sortable instance with the singleton to allow lookups later.
460 reg: function(s, id) {
464 Y.Sortable._sortables[id] = s;
469 * @param Sortable s A Sortable instance.
470 * @param String id (optional) The id of the sortable instance.
471 * @description Unregister a Sortable instance with the singleton.
473 unreg: function(s, id) {
477 if (id && Y.Sortable._sortables[id]) {
478 delete Y.Sortable._sortables[id];
481 Y.Object.each(Y.Sortable._sortables, function(v, k) {
483 delete Sortable._sortables[k];
489 Y.Sortable = Sortable;
493 * @description A Sortable node was moved with a copy.
494 * @param {Event.Facade} event An Event Facade object
495 * @param {Boolean} event.same Moved to the same list.
496 * @param {DD.Drag} event.drag The drag instance.
497 * @param {DD.Drop} event.drop The drop instance.
498 * @type {Event.Custom}
502 * @description A Sortable node was moved with a move.
503 * @param {Event.Facade} event An Event Facade object with the following specific property added:
504 * @param {Boolean} event.same Moved to the same list.
505 * @param {DD.Drag} event.drag The drag instance.
506 * @param {DD.Drop} event.drop The drop instance.
507 * @type {Event.Custom}
511 * @description A Sortable node was moved with an insert.
512 * @param {Event.Facade} event An Event Facade object with the following specific property added:
513 * @param {Boolean} event.same Moved to the same list.
514 * @param {DD.Drag} event.drag The drag instance.
515 * @param {DD.Drop} event.drop The drop instance.
516 * @type {Event.Custom}
520 * @description A Sortable node was moved with a swap.
521 * @param {Event.Facade} event An Event Facade object with the following specific property added:
522 * @param {Boolean} event.same Moved to the same list.
523 * @param {DD.Drag} event.drag The drag instance.
524 * @param {DD.Drop} event.drop The drop instance.
525 * @type {Event.Custom}
529 * @description A Sortable node was moved.
530 * @param {Event.Facade} event An Event Facade object with the following specific property added:
531 * @param {Boolean} event.same Moved to the same list.
532 * @param {DD.Drag} event.drag The drag instance.
533 * @param {DD.Drop} event.drop The drop instance.
534 * @type {Event.Custom}
539 }, '3.13.0', {"requires": ["dd-delegate", "dd-drop-plugin", "dd-proxy"]});