X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6746dc89c47ed01b165cc1152533605f97eb8e8d..refs/heads/master:/docs/source/DropZone2.html diff --git a/docs/source/DropZone2.html b/docs/source/DropZone2.html index 735a5299..cb8f5239 100644 --- a/docs/source/DropZone2.html +++ b/docs/source/DropZone2.html @@ -3,8 +3,8 @@
/** - * @class Ext.view.DropZone +/** + * @class Ext.grid.header.DropZone * @extends Ext.dd.DropZone * @private */ -Ext.define('Ext.view.DropZone', { +Ext.define('Ext.grid.header.DropZone', { extend: 'Ext.dd.DropZone', + colHeaderCls: Ext.baseCSSPrefix + 'column-header', + proxyOffsets: [-4, -9], - indicatorHtml: '<div class="x-grid-drop-indicator-left"></div><div class="x-grid-drop-indicator-right"></div>', - indicatorCls: 'x-grid-drop-indicator', - - constructor: function(config) { - var me = this; - Ext.apply(me, config); - - // Create a ddGroup unless one has been configured. - // User configuration of ddGroups allows users to specify which - // DD instances can interact with each other. Using one - // based on the id of the View would isolate it and mean it can only - // interact with a DragZone on the same View also using a generated ID. - if (!me.ddGroup) { - me.ddGroup = 'view-dd-zone-' + me.view.id; - } + constructor: function(headerCt){ + this.headerCt = headerCt; + this.ddGroup = this.getDDGroup(); + this.callParent([headerCt.el]); + }, - // The DropZone's encapsulating element is the View's main element. It must be this because drop gestures - // may require scrolling on hover near a scrolling boundary. In Ext 4.x two DD instances may not use the - // same element, so a DragZone on this same View must use the View's parent element as its element. - me.callParent([me.view.el]); + getDDGroup: function() { + return 'header-dd-zone-' + this.headerCt.up('[scrollerOwner]').id; }, -// Fire an event through the client DataView. Lock this DropZone during the event processing so that -// its data does not become corrupted by processing mouse events. - fireViewEvent: function() { - var me = this, - result; - - me.lock(); - result = me.view.fireEvent.apply(me.view, arguments); - me.unlock(); - return result; + getTargetFromEvent : function(e){ + return e.getTarget('.' + this.colHeaderCls); }, - getTargetFromEvent : function(e) { - var node = e.getTarget(this.view.getItemSelector()), - mouseY, nodeList, testNode, i, len, box; - -// Not over a row node: The content may be narrower than the View's encapsulating element, so return the closest. -// If we fall through because the mouse is below the nodes (or there are no nodes), we'll get an onContainerOver call. - if (!node) { - mouseY = e.getPageY(); - for (i = 0, nodeList = this.view.getNodes(), len = nodeList.length; i < len; i++) { - testNode = nodeList[i]; - box = Ext.fly(testNode).getBox(); - if (mouseY <= box.bottom) { - return testNode; - } - } + getTopIndicator: function() { + if (!this.topIndicator) { + this.topIndicator = Ext.DomHelper.append(Ext.getBody(), { + cls: "col-move-top", + html: " " + }, true); } - return node; + return this.topIndicator; }, - getIndicator: function() { - var me = this; - - if (!me.indicator) { - me.indicator = Ext.createWidget('component', { - html: me.indicatorHtml, - cls: me.indicatorCls, - ownerCt: me.view, - floating: true, - shadow: false - }); + getBottomIndicator: function() { + if (!this.bottomIndicator) { + this.bottomIndicator = Ext.DomHelper.append(Ext.getBody(), { + cls: "col-move-bottom", + html: " " + }, true); } - return me.indicator; + return this.bottomIndicator; }, - getPosition: function(e, node) { - var y = e.getXY()[1], - region = Ext.fly(node).getRegion(), - pos; + getLocation: function(e, t) { + var x = e.getXY()[0], + region = Ext.fly(t).getRegion(), + pos, header; - if ((region.bottom - y) >= (region.bottom - region.top) / 2) { - pos = "before"; - } else { + if ((region.right - x) <= (region.right - region.left) / 2) { pos = "after"; + } else { + pos = "before"; } - return pos; + return { + pos: pos, + header: Ext.getCmp(t.id), + node: t + }; }, - /** - * @private Determines whether the record at the specified offset from the passed record - * is in the drag payload. - * @param records - * @param record - * @param offset - * @returns {Boolean} True if the targeted record is in the drag payload - */ - containsRecordAtOffset: function(records, record, offset) { - if (!record) { + positionIndicator: function(draggedHeader, node, e){ + var location = this.getLocation(e, node), + header = location.header, + pos = location.pos, + nextHd = draggedHeader.nextSibling('gridcolumn:not([hidden])'), + prevHd = draggedHeader.previousSibling('gridcolumn:not([hidden])'), + region, topIndicator, bottomIndicator, topAnchor, bottomAnchor, + topXY, bottomXY, headerCtEl, minX, maxX; + + // Cannot drag beyond non-draggable start column + if (!header.draggable && header.getIndex() == 0) { return false; } - var view = this.view, - recordIndex = view.indexOf(record), - nodeBefore = view.getNode(recordIndex + offset), - recordBefore = nodeBefore ? view.getRecord(nodeBefore) : null; - return recordBefore && Ext.Array.contains(records, recordBefore); - }, + this.lastLocation = location; + + if ((draggedHeader !== header) && + ((pos === "before" && nextHd !== header) || + (pos === "after" && prevHd !== header)) && + !header.isDescendantOf(draggedHeader)) { + + // As we move in between different DropZones that are in the same + // group (such as the case when in a locked grid), invalidateDrop + // on the other dropZones. + var allDropZones = Ext.dd.DragDropManager.getRelated(this), + ln = allDropZones.length, + i = 0, + dropZone; - positionIndicator: function(node, data, e) { - var me = this, - view = me.view, - pos = me.getPosition(e, node), - overRecord = view.getRecord(node), - draggingRecords = data.records, - indicator, indicatorY; - - if (!Ext.Array.contains(draggingRecords, overRecord) && ( - pos == 'before' && !me.containsRecordAtOffset(draggingRecords, overRecord, -1) || - pos == 'after' && !me.containsRecordAtOffset(draggingRecords, overRecord, 1) - )) { - me.valid = true; - - if (me.overRecord != overRecord || me.currentPosition != pos) { - - indicatorY = Ext.fly(node).getY() - view.el.getY() - 1; - if (pos == 'after') { - indicatorY += Ext.fly(node).getHeight(); + for (; i < ln; i++) { + dropZone = allDropZones[i]; + if (dropZone !== this && dropZone.invalidateDrop) { + dropZone.invalidateDrop(); } - me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, indicatorY); + } + - // Cache the overRecord and the 'before' or 'after' indicator. - me.overRecord = overRecord; - me.currentPosition = pos; + this.valid = true; + topIndicator = this.getTopIndicator(); + bottomIndicator = this.getBottomIndicator(); + if (pos === 'before') { + topAnchor = 'tl'; + bottomAnchor = 'bl'; + } else { + topAnchor = 'tr'; + bottomAnchor = 'br'; } + topXY = header.el.getAnchorXY(topAnchor); + bottomXY = header.el.getAnchorXY(bottomAnchor); + + // constrain the indicators to the viewable section + headerCtEl = this.headerCt.el; + minX = headerCtEl.getLeft(); + maxX = headerCtEl.getRight(); + + topXY[0] = Ext.Number.constrain(topXY[0], minX, maxX); + bottomXY[0] = Ext.Number.constrain(bottomXY[0], minX, maxX); + + // adjust by offsets, this is to center the arrows so that they point + // at the split point + topXY[0] -= 4; + topXY[1] -= 9; + bottomXY[0] -= 4; + + // position and show indicators + topIndicator.setXY(topXY); + bottomIndicator.setXY(bottomXY); + topIndicator.show(); + bottomIndicator.show(); + // invalidate drop operation and hide indicators } else { - me.invalidateDrop(); + this.invalidateDrop(); } }, invalidateDrop: function() { - if (this.valid) { - this.valid = false; - this.getIndicator().hide(); - } + this.valid = false; + this.hideIndicators(); }, - // The mouse is over a View node onNodeOver: function(node, dragZone, e, data) { - var me = this; - - if (!Ext.Array.contains(data.records, me.view.getRecord(node))) { - me.positionIndicator(node, data, e); + if (data.header.el.dom !== node) { + this.positionIndicator(data.header, node, e); } - return me.valid ? me.dropAllowed : me.dropNotAllowed; + return this.valid ? this.dropAllowed : this.dropNotAllowed; }, - // Moved out of the DropZone without dropping. - // Remove drop position indicator - notifyOut: function(node, dragZone, e, data) { - var me = this; - - me.callParent(arguments); - delete me.overRecord; - delete me.currentPosition; - if (me.indicator) { - me.indicator.hide(); - } + hideIndicators: function() { + this.getTopIndicator().hide(); + this.getBottomIndicator().hide(); }, - // The mouse is past the end of all nodes (or there are no nodes) - onContainerOver : function(dd, e, data) { - var me = this, - view = me.view, - count = view.store.getCount(); + onNodeOut: function() { + this.hideIndicators(); + }, - // There are records, so position after the last one - if (count) { - me.positionIndicator(view.getNode(count - 1), data, e); - } + onNodeDrop: function(node, dragZone, e, data) { + if (this.valid) { + this.invalidateDrop(); + var hd = data.header, + lastLocation = this.lastLocation, + fromCt = hd.ownerCt, + fromIdx = fromCt.items.indexOf(hd), // Container.items is a MixedCollection + toCt = lastLocation.header.ownerCt, + toIdx = toCt.items.indexOf(lastLocation.header), + headerCt = this.headerCt, + groupCt, + scrollerOwner; - // No records, position the indicator at the top - else { - delete me.overRecord; - delete me.currentPosition; - me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, 0); - me.valid = true; - } - return me.dropAllowed; - }, + if (lastLocation.pos === 'after') { + toIdx++; + } - onContainerDrop : function(dd, e, data) { - return this.onNodeDrop(dd, null, e, data); - }, + // If we are dragging in between two HeaderContainers that have had the lockable + // mixin injected we will lock/unlock headers in between sections. Note that lockable + // does NOT currently support grouped headers. + if (fromCt !== toCt && fromCt.lockableInjected && toCt.lockableInjected && toCt.lockedCt) { + scrollerOwner = fromCt.up('[scrollerOwner]'); + scrollerOwner.lock(hd, toIdx); + } else if (fromCt !== toCt && fromCt.lockableInjected && toCt.lockableInjected && fromCt.lockedCt) { + scrollerOwner = fromCt.up('[scrollerOwner]'); + scrollerOwner.unlock(hd, toIdx); + } else { + // If dragging rightwards, then after removal, the insertion index will be one less when moving + // in between the same container. + if ((fromCt === toCt) && (toIdx > fromCt.items.indexOf(hd))) { + toIdx--; + } - onNodeDrop: function(node, dragZone, e, data) { - var me = this, - dropped = false, - - // Create a closure to perform the operation which the event handler may use. - // Users may now return <code>false</code> from the beforedrop handler, and perform any kind - // of asynchronous processing such as an Ext.Msg.confirm, or an Ajax request, - // and complete the drop gesture at some point in the future by calling this function. - processDrop = function () { - me.invalidateDrop(); - me.handleNodeDrop(data, me.overRecord, me.currentPosition); - dropped = true; - me.fireViewEvent('drop', node, data, me.overRecord, me.currentPosition); - }, - performOperation = false; - - if (me.valid) { - performOperation = me.fireViewEvent('beforedrop', node, data, me.overRecord, me.currentPosition, processDrop); - if (performOperation !== false) { - // If the processDrop function was called in the event handler, do not do it again. - if (!dropped) { - processDrop(); + // Remove dragged header from where it was without destroying it or relaying its Container + if (fromCt !== toCt) { + fromCt.suspendLayout = true; + fromCt.remove(hd, false); + fromCt.suspendLayout = false; + } + + // Dragged the last header out of the fromCt group... The fromCt group must die + if (fromCt.isGroupHeader) { + if (!fromCt.items.getCount()) { + groupCt = fromCt.ownerCt; + groupCt.suspendLayout = true; + groupCt.remove(fromCt, false); + fromCt.el.dom.parentNode.removeChild(fromCt.el.dom); + groupCt.suspendLayout = false; + } else { + fromCt.minWidth = fromCt.getWidth() - hd.getWidth(); + fromCt.setWidth(fromCt.minWidth); + } + } + + // Move dragged header into its drop position + toCt.suspendLayout = true; + if (fromCt === toCt) { + toCt.move(fromIdx, toIdx); + } else { + toCt.insert(toIdx, hd); + } + toCt.suspendLayout = false; + + // Group headers acquire the aggregate width of their child headers + // Therefore a child header may not flex; it must contribute a fixed width. + // But we restore the flex value when moving back into the main header container + if (toCt.isGroupHeader) { + hd.savedFlex = hd.flex; + delete hd.flex; + hd.width = hd.getWidth(); + // When there was previously a flex, we need to ensure we don't count for the + // border twice. + toCt.minWidth = toCt.getWidth() + hd.getWidth() - (hd.savedFlex ? 1 : 0); + toCt.setWidth(toCt.minWidth); + } else { + if (hd.savedFlex) { + hd.flex = hd.savedFlex; + delete hd.width; + } + } + + + // Refresh columns cache in case we remove an emptied group column + headerCt.purgeCache(); + headerCt.doLayout(); + headerCt.onHeaderMoved(hd, fromIdx, toIdx); + // Emptied group header can only be destroyed after the header and grid have been refreshed + if (!fromCt.items.getCount()) { + fromCt.destroy(); } } } - return performOperation; } });