3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.grid.plugin.HeaderResizer
17 * @extends Ext.util.Observable
19 * Plugin to add header resizing functionality to a HeaderContainer.
20 * Always resizing header to the left of the splitter you are resizing.
22 * Todo: Consider RTL support, columns would always calculate to the right of
23 * the splitter instead of to the left.
25 Ext.define('Ext.grid.plugin.HeaderResizer', {
26 extend: 'Ext.util.Observable',
27 requires: ['Ext.dd.DragTracker', 'Ext.util.Region'],
28 alias: 'plugin.gridheaderresizer',
33 * @cfg {Boolean} dynamic
34 * Set to true to resize on the fly rather than using a proxy marker. Defaults to false.
40 colHeaderCls: Ext.baseCSSPrefix + 'column-header',
44 wResizeCursor: 'col-resize',
45 eResizeCursor: 'col-resize',
46 // not using w and e resize bc we are only ever resizing one
48 //wResizeCursor: Ext.isWebKit ? 'w-resize' : 'col-resize',
49 //eResizeCursor: Ext.isWebKit ? 'e-resize' : 'col-resize',
51 init: function(headerCt) {
52 this.headerCt = headerCt;
53 headerCt.on('render', this.afterHeaderRender, this, {single: true});
58 * AbstractComponent calls destroy on all its plugins at destroy time.
62 this.tracker.destroy();
66 afterHeaderRender: function() {
67 var headerCt = this.headerCt,
70 headerCt.mon(el, 'mousemove', this.onHeaderCtMouseMove, this);
72 this.tracker = Ext.create('Ext.dd.DragTracker', {
73 disabled: this.disabled,
74 onBeforeStart: Ext.Function.bind(this.onBeforeStart, this),
75 onStart: Ext.Function.bind(this.onStart, this),
76 onDrag: Ext.Function.bind(this.onDrag, this),
77 onEnd: Ext.Function.bind(this.onEnd, this),
84 // As we mouse over individual headers, change the cursor to indicate
85 // that resizing is available, and cache the resize target header for use
86 // if/when they mousedown.
87 onHeaderCtMouseMove: function(e, t) {
88 if (this.headerCt.dragging) {
90 this.activeHd.el.dom.style.cursor = '';
94 var headerEl = e.getTarget('.' + this.colHeaderCls, 3, true),
95 overHeader, resizeHeader;
98 overHeader = Ext.getCmp(headerEl.id);
100 // On left edge, we are resizing the previous non-hidden, base level column.
101 if (overHeader.isOnLeftEdge(e)) {
102 resizeHeader = overHeader.previousNode('gridcolumn:not([hidden]):not([isGroupHeader])');
104 // Else, if on the right edge, we're resizing the column we are over
105 else if (overHeader.isOnRightEdge(e)) {
106 resizeHeader = overHeader;
108 // Between the edges: we are not resizing
115 // If we're attempting to resize a group header, that cannot be resized,
116 // so find its last base level column header; Group headers are sized
117 // by the size of their child headers.
118 if (resizeHeader.isGroupHeader) {
119 resizeHeader = resizeHeader.getVisibleGridColumns();
120 resizeHeader = resizeHeader[resizeHeader.length - 1];
123 if (resizeHeader && !(resizeHeader.fixed || this.disabled)) {
124 this.activeHd = resizeHeader;
125 overHeader.el.dom.style.cursor = this.eResizeCursor;
129 overHeader.el.dom.style.cursor = '';
130 delete this.activeHd;
136 // only start when there is an activeHd
137 onBeforeStart : function(e){
138 var t = e.getTarget();
139 // cache the activeHd because it will be cleared.
140 this.dragHd = this.activeHd;
142 if (!!this.dragHd && !Ext.fly(t).hasCls('x-column-header-trigger') && !this.headerCt.dragging) {
143 //this.headerCt.dragging = true;
144 this.tracker.constrainTo = this.getConstrainRegion();
147 this.headerCt.dragging = false;
152 // get the region to constrain to, takes into account max and min col widths
153 getConstrainRegion: function() {
154 var dragHdEl = this.dragHd.el,
155 region = Ext.util.Region.getRegion(dragHdEl);
157 return region.adjust(
159 this.maxColWidth - dragHdEl.getWidth(),
165 // initialize the left and right hand side markers around
166 // the header that we are resizing
167 onStart: function(e){
170 dragHdEl = dragHd.el,
171 width = dragHdEl.getWidth(),
172 headerCt = me.headerCt,
175 if (me.dragHd && !Ext.fly(t).hasCls('x-column-header-trigger')) {
176 headerCt.dragging = true;
179 me.origWidth = width;
181 // setup marker proxies
183 var xy = dragHdEl.getXY(),
184 gridSection = headerCt.up('[scrollerOwner]'),
185 dragHct = me.dragHd.up(':not([isGroupHeader])'),
186 firstSection = dragHct.up(),
187 lhsMarker = gridSection.getLhsMarker(),
188 rhsMarker = gridSection.getRhsMarker(),
189 el = rhsMarker.parent(),
190 offsetLeft = el.getLeft(true),
191 offsetTop = el.getTop(true),
192 topLeft = el.translatePoints(xy),
193 markerHeight = firstSection.body.getHeight() + headerCt.getHeight(),
194 top = topLeft.top - offsetTop;
196 lhsMarker.setTop(top);
197 rhsMarker.setTop(top);
198 lhsMarker.setHeight(markerHeight);
199 rhsMarker.setHeight(markerHeight);
200 lhsMarker.setLeft(topLeft.left - offsetLeft);
201 rhsMarker.setLeft(topLeft.left + width - offsetLeft);
205 // synchronize the rhsMarker with the mouse movement
208 var xy = this.tracker.getXY('point'),
209 gridSection = this.headerCt.up('[scrollerOwner]'),
210 rhsMarker = gridSection.getRhsMarker(),
211 el = rhsMarker.parent(),
212 topLeft = el.translatePoints(xy),
213 offsetLeft = el.getLeft(true);
215 rhsMarker.setLeft(topLeft.left - offsetLeft);
216 // Resize as user interacts
223 this.headerCt.dragging = false;
226 var dragHd = this.dragHd,
227 gridSection = this.headerCt.up('[scrollerOwner]'),
228 lhsMarker = gridSection.getLhsMarker(),
229 rhsMarker = gridSection.getRhsMarker(),
230 currWidth = dragHd.getWidth(),
231 offset = this.tracker.getOffset('point'),
235 lhsMarker.setLeft(offscreen);
236 rhsMarker.setLeft(offscreen);
242 doResize: function() {
244 var dragHd = this.dragHd,
246 offset = this.tracker.getOffset('point');
253 // If HeaderContainer is configured forceFit, inhibit upstream layout notification, so that
254 // we can also shrink the following Header by an equal amount, and *then* inform the upstream layout.
255 if (this.headerCt.forceFit) {
256 nextHd = dragHd.nextNode('gridcolumn:not([hidden]):not([isGroupHeader])');
258 this.headerCt.componentLayout.layoutBusy = true;
262 // Non-flexed Headers may never be squeezed in the event of a shortfall so
263 // always set the minWidth to their current width.
264 dragHd.minWidth = this.origWidth + offset[0];
265 dragHd.setWidth(dragHd.minWidth);
267 // In the case of forceFit, change the following Header width.
268 // Then apply the two width changes by laying out the owning HeaderContainer
271 nextHd.setWidth(nextHd.getWidth() - offset[0]);
272 this.headerCt.componentLayout.layoutBusy = false;
273 this.headerCt.doComponentLayout();
278 disable: function() {
279 this.disabled = true;
281 this.tracker.disable();
286 this.disabled = false;
288 this.tracker.enable();