/** * */Ext.define('Ext.ux.DataView.DragSelector', { requires: ['Ext.dd.DragTracker', 'Ext.util.Region'], alias: 'plugin.dataviewdragselector', /** * Initializes the plugin by setting up the drag tracker */ init: function(dataview) { var scroller = dataview.getScrollable(); // If the client dataview is scrollable, and this is a PointerEvents device // we cannot intercept the pointer to inplement dragselect. if (scroller && (scroller.getX() || scroller.getY()) && (Ext.supports.PointerEvents || Ext.supports.MSPointerEvents)) { //<debug> Ext.log.warn('DragSelector not available on PointerEvent devices'); //</debug> return; } /** * @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, onBeforeStart: this.onBeforeStart, onStart: this.onStart.bind(this), onDrag: this.onDrag.bind(this), onEnd: Ext.Function.createDelayed(this.onEnd, 100, this) }); /** * @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.event.Event} e The click event */ onStart: function(e) { var 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 this.fillRegions(); this.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.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.event.Event} e The drag event */ onDrag: function(e) { var selModel = this.dataview.getSelectionModel(), dragRegion = this.dragRegion, bodyRegion = this.bodyRegion, proxy = this.getProxy(), regions = this.regions, length = regions.length, startXY = this.tracker.startXY, currentXY = this.tracker.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.setBox(dragRegion); for (i = 0; i < length; i++) { region = regions[i]; selected = dragRegion.intersect(region); if (selected) { selModel.select(i, true); } else { selModel.deselect(i); } } }, /** * @method * @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.event.Event} e The event object */ onEnd: function(e) { var dataview = this.dataview, selModel = dataview.getSelectionModel(); // eslint-disable-line no-unused-vars this.dragging = false; this.getProxy().hide(); }, /** * @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(); }});