X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/examples/ux/DataView/DragSelector.js diff --git a/examples/ux/DataView/DragSelector.js b/examples/ux/DataView/DragSelector.js new file mode 100644 index 00000000..6613cff4 --- /dev/null +++ b/examples/ux/DataView/DragSelector.js @@ -0,0 +1,193 @@ +/** + * @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 {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 {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 {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(); + } +}); \ No newline at end of file