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
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();
|
|
}
|
|
}); |