delegate.js revision 482da2d388e0f999f372383039af944e21bc717b
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * Provides the ability to drag multiple nodes under a container element using only one Y.DD.Drag instance as a delegate.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @module dd
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @submodule dd-delegate
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * Provides the ability to drag multiple nodes under a container element using only one Y.DD.Drag instance as a delegate.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @class Delegate
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @extends Base
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @constructor
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @namespace DD
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai var Delegate = function(o) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai Delegate.superclass.constructor.apply(this, arguments);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai },
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai CONT = 'container',
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai NODES = 'nodes',
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai _tmpNode = Y.Node.create('<div>Temp Node</div>');
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai Y.extend(Delegate, Y.Base, {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @property dd
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @description A reference to the temporary dd instance used under the hood.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai dd: null,
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @property _shimState
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @private
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @description The state of the Y.DD.DDM._noShim property to it can be reset.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai _shimState: null,
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @private
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @method _onNodeChange
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @description Listens to the nodeChange event and sets the dragNode on the temp dd instance.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @param {Event} e The Event.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai _onNodeChange: function(e) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai this.set('dragNode', e.newVal);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai },
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @private
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @method _afterDragEnd
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @description Listens for the drag:end event and updates the temp dd instance.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @param {Event} e The Event.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai _afterDragEnd: function(e) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai var self = this;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai Y.DD.DDM._noShim = self._shimState;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai self.set('lastNode', self.dd.get('node'));
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai self.get('lastNode').removeClass(Y.DD.DDM.CSS_PREFIX + '-dragging');
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai self.dd._unprep();
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai self.dd.set('node', _tmpNode);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai },
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @private
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @method _onDelegate
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @description The callback for the Y.DD.Delegate instance used
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @param {Event} e The MouseDown Event.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai _onDelegate: function(e) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai var tar = e.currentTarget,
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai self = this, dd = self.dd;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai if (tar.test(self.get(NODES)) && !tar.test(self.get('invalid'))) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai self._shimState = Y.DD.DDM._noShim;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai Y.DD.DDM._noShim = true;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai self.set('currentNode', tar);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai dd.set('node', tar);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai if (dd.proxy) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai dd.set('dragNode', Y.DD.DDM._proxy);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai } else {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai dd.set('dragNode', tar);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai }
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai dd._prep();
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai dd.fire('drag:mouseDown', { ev: e });
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai }
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai },
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @private
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @method _onMouseEnter
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @description Sets the target shim state
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @param {Event} e The MouseEnter Event
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai _onMouseEnter: function(e) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai this._shimState = Y.DD.DDM._noShim;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai Y.DD.DDM._noShim = true;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai },
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai /**
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @private
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @method _onMouseLeave
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @description Resets the target shim state
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai * @param {Event} e The MouseLeave Event
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai */
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai _onMouseLeave: function(e) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai Y.DD.DDM._noShim = this._shimState;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai },
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai initializer: function(cfg) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai if (!Y.Object.hasKey(cfg, 'bubbleTargets')) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai this.addTarget(Y.DD.DDM);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai }
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai //Create a tmp DD instance under the hood.
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai var conf = this.get('dragConfig') || {},
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai cont = this.get(CONT);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai conf.node = _tmpNode.cloneNode(true);
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai conf.bubbleTargets = this;
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai if (this.get('handles')) {
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai conf.handles = this.get('handles');
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai }
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai
6c96442b6a372e466ea59417a4e147d4fbd4a006Satyen Desai this.dd = new Y.DD.Drag(conf);
//On end drag, detach the listeners
this.dd.after('drag:end', Y.bind(this._afterDragEnd, this));
this.dd.on('dragNodeChange', Y.bind(this._onNodeChange, this));
//Attach the delegate to the container
Y.delegate('mousedown', Y.bind(this._onDelegate, this), cont, this.get(NODES));
Y.on('mouseenter', Y.bind(this._onMouseEnter, this), cont);
Y.on('mouseleave', Y.bind(this._onMouseLeave, this), cont);
Y.later(10, this, this.syncTargets);
Y.DD.DDM.regDelegate(this);
},
/**
* @method syncTargets
* @description Applies the Y.Plugin.Drop to all nodes matching the cont + nodes selector query.
* @param {String} group The default group to assign this target to. Optional.
* @return {Self}
* @chainable
*/
syncTargets: function(group) {
if (!Y.Plugin.Drop) {
return;
}
var items, groups, self = this;
if (self.get('target')) {
items = Y.one(self.get(CONT)).all(self.get(NODES));
groups = self.dd.get('groups');
if (group) {
groups = [group];
}
items.each(function(i) {
self.createDrop(i, groups);
});
}
return self;
},
/**
* @method createDrop
* @description Apply the Drop plugin to this node
* @param {Node} node The Node to apply the plugin to
* @param {Array} groups The default groups to assign this target to.
* @return Node
*/
createDrop: function(node, groups) {
var config = {
useShim: false,
bubbleTargets: this
};
if (!node.drop) {
node.plug(Y.Plugin.Drop, config);
}
node.drop.set('groups', groups);
return node;
},
destructor: function() {
if (this.dd) {
this.dd.destroy();
}
if (Y.Plugin.Drop) {
var targets = Y.one(this.get(CONT)).all(this.get(NODES));
targets.unplug(Y.Plugin.Drop);
}
}
}, {
NAME: 'delegate',
ATTRS: {
/**
* @attribute container
* @description A selector query to get the container to listen for mousedown events on. All "nodes" should be a child of this container.
* @type String
*/
container: {
value: 'body'
},
/**
* @attribute nodes
* @description A selector query to get the children of the "container" to make draggable elements from.
* @type String
*/
nodes: {
value: '.dd-draggable'
},
/**
* @attribute invalid
* @description A selector query to test a node to see if it's an invalid item.
* @type String
*/
invalid: {
value: ''
},
/**
* @attribute lastNode
* @description Y.Node instance of the last item dragged.
* @type Node
*/
lastNode: {
value: _tmpNode
},
/**
* @attribute currentNode
* @description Y.Node instance of the dd node.
* @type Node
*/
currentNode: {
value: _tmpNode
},
/**
* @attribute dragNode
* @description Y.Node instance of the dd dragNode.
* @type Node
*/
dragNode: {
value: _tmpNode
},
/**
* @attribute over
* @description Is the mouse currently over the container
* @type Boolean
*/
over: {
value: false
},
/**
* @attribute target
* @description Should the items also be a drop target.
* @type Boolean
*/
target: {
value: false
},
/**
* @attribute dragConfig
* @description The default config to be used when creating the DD instance.
* @type Object
*/
dragConfig: {
value: null
},
/**
* @attribute handles
* @description The handles config option added to the temp DD instance.
* @type Array
*/
handles: {
value: null
}
}
});
Y.mix(Y.DD.DDM, {
/**
* @private
* @for DDM
* @property _delegates
* @description Holder for all Y.DD.Delegate instances
* @type Array
*/
_delegates: [],
/**
* @for DDM
* @method regDelegate
* @description Register a Delegate with the DDM
*/
regDelegate: function(del) {
this._delegates.push(del);
},
/**
* @for DDM
* @method getDelegate
* @description Get a delegate instance from a container node
* @returns Y.DD.Delegate
*/
getDelegate: function(node) {
var del = null;
node = Y.one(node);
Y.each(this._delegates, function(v) {
if (node.test(v.get(CONT))) {
del = v;
}
}, this);
return del;
}
});
Y.namespace('DD');
Y.DD.Delegate = Delegate;