PDA

View Full Version : Data View Drag and Drop to Simulate JQ UI Draggable



Jangla
24 Oct 2014, 6:42 AM
I'v ebeen building out a little drag and drop data view in ExtJS and have found some helpful code which I've made some very minor adjustments to in order to have a plugin that enables drag and drop of items within a data view:





/**
* Plugin (ptype = 'viewsortable') that makes a view "Sortable"
* via drag/drop.
*/
Ext.define('Utils.plugins.Sortable', {


extend: 'Ext.AbstractPlugin',


alias: 'plugin.viewsortable',


mixins: {
observable: 'Ext.util.Observable'
},


config: {


/**
* the event which the plugin should listen on the view,
*
* at this moment the plugin initiializes it's drag and drop zones
*/
eventName: 'render',


/**
* the class which will be added to the dragged node, then it enters a
* valid target
*
*/
highlightClass: 'view-drag-highlight'
},


//logger: log4javascript.getLogger('Utils.plugin.Sortable'),
logger: {
debug: function (msg) {
return null;
//console.log(msg);
}
},


/**
* initialize the plugin
*
* @private
*/
init: function (view) {
this.mixins.observable.constructor.call(this);


this.logger.debug('sortable plugin init:', view);
this.logger.debug('using event:', this.getEventName());


this.addEvents(


/**
* @event
* event gets fired after a drag and drop action
* was successful
*
* @param {Utils.plugins.Sortable} this the plugin
* @param {Ext.data.Record} draggedRecord the dragged record
* @param {Ext.data.Record} targetRecord the record on which the other has droped
*/
'aftersort'
);


this.view = view;
view.on(this.getEventName(), this.initDragDrop, this);
},


/**
* initialize the drag and drop behavior on the view
*
* @private
*/
initDragDrop: function () {


this.logger.debug('init drag and drop');


var me = this;
var v = this.view;


var dragZone = Ext.create('Ext.dd.DragZone', this.view.getEl(), {


// On receipt of a mousedown event, see if it is within a DataView node.
// Return a drag data object if so.
getDragData: function (e) {


// Use the DataView's own itemSelector (a mandatory property) to
// test if the mousedown is within one of the DataView's nodes.
var dragHandleEl = e.getTarget(me.dragHandle || v.itemSelector, 10);
var sourceEl = e.getTarget(v.itemSelector, 10);


// If the mousedown is within a DataView node, clone the node to produce
// a ddel element for use by the drag proxy. Also add application data
// to the returned data object.


// we have added the ability to have a clone node tpl in case you need your cloned node to look drastically different
if (dragHandleEl && sourceEl) {
d = sourceEl.cloneNode(true);
Ext.fly(d).select('.hide-on-drag').hide();
d.id = Ext.id();
return {
ddel: d,
sourceEl: sourceEl,
repairXY: Ext.fly(sourceEl).getXY(),
sourceStore: v.store,
draggedRecord: v.getRecord(sourceEl)
};
}
},


// Provide coordinates for the proxy to slide back to on failed drag.
// This is the original XY coordinates of the draggable element captured
// in the getDragData method.
getRepairXY: function () {
return this.dragData.repairXY;
}
});


var dropZone = Ext.create('Ext.dd.DropZone', this.view.getEl(), {


// If the mouse is over a grid row, return that node. This is
// provided as the "target" parameter in all "onNodeXXXX" node event handling functions
getTargetFromEvent: function (e) {
return e.getTarget(v.itemSelector);
},


// On entry into a target node, highlight that node.
onNodeEnter: function (target, dd, e, data) {
Ext.fly(target).addCls(me.getHighlightClass());
},


// On exit from a target node, unhighlight that node.
onNodeOut: function (target, dd, e, data) {
Ext.fly(target).removeCls(me.getHighlightClass());
},


// While over a target node, return the default drop allowed class which
// places a "tick" icon into the drag proxy.
onNodeOver: function (target, dd, e, data) {
return Ext.dd.DropZone.prototype.dropAllowed;
},


// On node drop we can interrogate the target to find the underlying
// application object that is the real target of the dragged data.
// In this case, it is a Record in the GridPanel's Store.
// We can use the data set up by the DragZone's getDragData method to read
// any data we decided to attach in the DragZone's getDragData method.
onNodeDrop: function (target, dd, e, data) {
me.logger.debug('onNodeDrop target', target);
me.logger.debug('onNodeDrop data', data);


var store = v.getStore();


var index = v.indexOf(target);
me.logger.debug('onNodeDrop dropped on', index);


var r = store.getAt(index);
store.suspendAutoSync();
store.remove(data.draggedRecord);
store.insert(index, [data.draggedRecord]);
store.resumeAutoSync();
v.fireEvent('orderchange', me );
me.fireEvent('aftersort', me, data.draggedRecord, r);


// Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +
// ' on Record id ' + r.id);
return true;
}
});
}
});


However, what I really want is for the UX to follow more in the footsteps of JQuery UI's Sortable as demonstrated here: http://jqueryui.com/sortable/

Note that the "dragged item" no longer appears in the list and a blank space appears where ever the drop zone currently is. This does not happen in ExtJS.

Anyone done this before and have some pointers?

slemmon
28 Oct 2014, 3:37 PM
Hi,

I've not seen that sort of functionality in a dataview, though it does exist from the framework as a ux for containers. You might check out the source of the BoxReorderer class to get some ideas:

http://docs.sencha.com/extjs/4.2.3/#!/api/Ext.ux.BoxReorderer

Example:
http://dev.sencha.com/ext/5.0.1/examples/toolbar/reorderable.html