You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
6.6 KiB
JavaScript

/**
* @class Ext.ux.DataView.DragSelector
* @extends Object
* @author Ed Spencer
*
*/
Ext.define('Ext.ux.DataView.DragSelector', {
requires: ['Ext.dd.DragTracker', 'Ext.util.Region'],
/**
* Initializes the plugin by setting up the drag tracker
*/
init: function(dataview) {
/**
* @property dataview
* @type Ext.view.View
* The DataView bound to this instance
*/
this.dataview = dataview;
dataview.mon(dataview, {
beforecontainerclick: this.cancelClick,
scope: this,
render: {
fn: this.onRender,
scope: this,
single: true
}
});
},
/**
* @private
* Called when the attached DataView is rendered. This sets up the DragTracker instance that will be used
* to created a dragged selection area
*/
onRender: function() {
/**
* @property tracker
* @type Ext.dd.DragTracker
* The DragTracker attached to this instance. Note that the 4 on* functions are called in the scope of the
* DragTracker ('this' refers to the DragTracker inside those functions), so we pass a reference to the
* DragSelector so that we can call this class's functions.
*/
this.tracker = Ext.create('Ext.dd.DragTracker', {
dataview: this.dataview,
el: this.dataview.el,
dragSelector: this,
onBeforeStart: this.onBeforeStart,
onStart: this.onStart,
onDrag : this.onDrag,
onEnd : this.onEnd
});
/**
* @property dragRegion
* @type Ext.util.Region
* Represents the region currently dragged out by the user. This is used to figure out which dataview nodes are
* in the selected area and to set the size of the Proxy element used to highlight the current drag area
*/
this.dragRegion = Ext.create('Ext.util.Region');
},
/**
* @private
* Listener attached to the DragTracker's onBeforeStart event. Returns false if the drag didn't start within the
* DataView's el
*/
onBeforeStart: function(e) {
return e.target == this.dataview.getEl().dom;
},
/**
* @private
* Listener attached to the DragTracker's onStart event. Cancel's the DataView's containerclick event from firing
* and sets the start co-ordinates of the Proxy element. Clears any existing DataView selection
* @param {Ext.EventObject} e The click event
*/
onStart: function(e) {
var dragSelector = this.dragSelector,
dataview = this.dataview;
// Flag which controls whether the cancelClick method vetoes the processing of the DataView's containerclick event.
// On IE (where else), this needs to remain set for a millisecond after mouseup because even though the mouse has
// moved, the mouseup will still trigger a click event.
this.dragging = true;
//here we reset and show the selection proxy element and cache the regions each item in the dataview take up
dragSelector.fillRegions();
dragSelector.getProxy().show();
dataview.getSelectionModel().deselectAll();
},
/**
* @private
* Reusable handler that's used to cancel the container click event when dragging on the dataview. See onStart for
* details
*/
cancelClick: function() {
return !this.tracker.dragging;
},
/**
* @private
* Listener attached to the DragTracker's onDrag event. Figures out how large the drag selection area should be and
* updates the proxy element's size to match. Then iterates over all of the rendered items and marks them selected
* if the drag region touches them
* @param {Ext.EventObject} e The drag event
*/
onDrag: function(e) {
var dragSelector = this.dragSelector,
selModel = dragSelector.dataview.getSelectionModel(),
dragRegion = dragSelector.dragRegion,
bodyRegion = dragSelector.bodyRegion,
proxy = dragSelector.getProxy(),
regions = dragSelector.regions,
length = regions.length,
startXY = this.startXY,
currentXY = this.getXY(),
minX = Math.min(startXY[0], currentXY[0]),
minY = Math.min(startXY[1], currentXY[1]),
width = Math.abs(startXY[0] - currentXY[0]),
height = Math.abs(startXY[1] - currentXY[1]),
region, selected, i;
Ext.apply(dragRegion, {
top: minY,
left: minX,
right: minX + width,
bottom: minY + height
});
dragRegion.constrainTo(bodyRegion);
proxy.setRegion(dragRegion);
for (i = 0; i < length; i++) {
region = regions[i];
selected = dragRegion.intersect(region);
if (selected) {
selModel.select(i, true);
} else {
selModel.deselect(i);
}
}
},
/**
* @private
* Listener attached to the DragTracker's onEnd event. This is a delayed function which executes 1
* millisecond after it has been called. This is because the dragging flag must remain active to cancel
* the containerclick event which the mouseup event will trigger.
* @param {Ext.EventObject} e The event object
*/
onEnd: Ext.Function.createDelayed(function(e) {
var dataview = this.dataview,
selModel = dataview.getSelectionModel(),
dragSelector = this.dragSelector;
this.dragging = false;
dragSelector.getProxy().hide();
}, 1),
/**
* @private
* Creates a Proxy element that will be used to highlight the drag selection region
* @return {Ext.Element} The Proxy element
*/
getProxy: function() {
if (!this.proxy) {
this.proxy = this.dataview.getEl().createChild({
tag: 'div',
cls: 'x-view-selector'
});
}
return this.proxy;
},
/**
* @private
* Gets the region taken up by each rendered node in the DataView. We use these regions to figure out which nodes
* to select based on the selector region the user has dragged out
*/
fillRegions: function() {
var dataview = this.dataview,
regions = this.regions = [];
dataview.all.each(function(node) {
regions.push(node.getRegion());
});
this.bodyRegion = dataview.getEl().getRegion();
}
});