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 Ext.define('Ext.grid.plugin.HeaderResizer', {
23 extend: 'Ext.util.Observable',
24 requires: ['Ext.dd.DragTracker', 'Ext.util.Region'],
25 alias: 'plugin.gridheaderresizer',
30 * @cfg {Boolean} dynamic
31 * Set to true to resize on the fly rather than using a proxy marker. Defaults to false.
37 colHeaderCls: Ext.baseCSSPrefix + 'column-header',
41 wResizeCursor: 'col-resize',
42 eResizeCursor: 'col-resize',
43 // not using w and e resize bc we are only ever resizing one
45 //wResizeCursor: Ext.isWebKit ? 'w-resize' : 'col-resize',
46 //eResizeCursor: Ext.isWebKit ? 'e-resize' : 'col-resize',
48 init: function(headerCt) {
49 this.headerCt = headerCt;
50 headerCt.on('render', this.afterHeaderRender, this, {single: true});
55 * AbstractComponent calls destroy on all its plugins at destroy time.
59 this.tracker.destroy();
63 afterHeaderRender: function() {
64 var headerCt = this.headerCt,
67 headerCt.mon(el, 'mousemove', this.onHeaderCtMouseMove, this);
69 this.tracker = Ext.create('Ext.dd.DragTracker', {
70 disabled: this.disabled,
71 onBeforeStart: Ext.Function.bind(this.onBeforeStart, this),
72 onStart: Ext.Function.bind(this.onStart, this),
73 onDrag: Ext.Function.bind(this.onDrag, this),
74 onEnd: Ext.Function.bind(this.onEnd, this),
81 // As we mouse over individual headers, change the cursor to indicate
82 // that resizing is available, and cache the resize target header for use
83 // if/when they mousedown.
84 onHeaderCtMouseMove: function(e, t) {
85 if (this.headerCt.dragging) {
87 this.activeHd.el.dom.style.cursor = '';
91 var headerEl = e.getTarget('.' + this.colHeaderCls, 3, true),
92 overHeader, resizeHeader;
95 overHeader = Ext.getCmp(headerEl.id);
97 // On left edge, go back to the previous non-hidden header.
98 if (overHeader.isOnLeftEdge(e)) {
99 resizeHeader = overHeader.previousNode('gridcolumn:not([hidden])');
102 // Else, if on the right edge, we're resizing the column we are over
103 else if (overHeader.isOnRightEdge(e)) {
104 resizeHeader = overHeader;
106 // Between the edges: we are not resizing
113 // If we're attempting to resize a group header, that cannot be resized,
114 // so find its last visible leaf header; Group headers are sized
115 // by the size of their child headers.
116 if (resizeHeader.isGroupHeader) {
117 resizeHeader = resizeHeader.down(':not([isGroupHeader]):not([hidden]):last');
120 // Check if the header is resizable. Continue checking the old "fixed" property, bug also
121 // check whether the resizablwe property is set to false.
122 if (resizeHeader && !(resizeHeader.fixed || (resizeHeader.resizable === false) || this.disabled)) {
123 this.activeHd = resizeHeader;
124 overHeader.el.dom.style.cursor = this.eResizeCursor;
128 overHeader.el.dom.style.cursor = '';
129 delete this.activeHd;
135 // only start when there is an activeHd
136 onBeforeStart : function(e){
137 var t = e.getTarget();
138 // cache the activeHd because it will be cleared.
139 this.dragHd = this.activeHd;
141 if (!!this.dragHd && !Ext.fly(t).hasCls('x-column-header-trigger') && !this.headerCt.dragging) {
142 //this.headerCt.dragging = true;
143 this.tracker.constrainTo = this.getConstrainRegion();
146 this.headerCt.dragging = false;
151 // get the region to constrain to, takes into account max and min col widths
152 getConstrainRegion: function() {
153 var dragHdEl = this.dragHd.el,
154 region = Ext.util.Region.getRegion(dragHdEl);
156 return region.adjust(
158 this.maxColWidth - dragHdEl.getWidth(),
164 // initialize the left and right hand side markers around
165 // the header that we are resizing
166 onStart: function(e){
169 dragHdEl = dragHd.el,
170 width = dragHdEl.getWidth(),
171 headerCt = me.headerCt,
174 if (me.dragHd && !Ext.fly(t).hasCls('x-column-header-trigger')) {
175 headerCt.dragging = true;
178 me.origWidth = width;
180 // setup marker proxies
182 var xy = dragHdEl.getXY(),
183 gridSection = headerCt.up('[scrollerOwner]'),
184 dragHct = me.dragHd.up(':not([isGroupHeader])'),
185 firstSection = dragHct.up(),
186 lhsMarker = gridSection.getLhsMarker(),
187 rhsMarker = gridSection.getRhsMarker(),
188 el = rhsMarker.parent(),
189 offsetLeft = el.getLeft(true),
190 offsetTop = el.getTop(true),
191 topLeft = el.translatePoints(xy),
192 markerHeight = firstSection.body.getHeight() + headerCt.getHeight(),
193 top = topLeft.top - offsetTop;
195 lhsMarker.setTop(top);
196 rhsMarker.setTop(top);
197 lhsMarker.setHeight(markerHeight);
198 rhsMarker.setHeight(markerHeight);
199 lhsMarker.setLeft(topLeft.left - offsetLeft);
200 rhsMarker.setLeft(topLeft.left + width - offsetLeft);
204 // synchronize the rhsMarker with the mouse movement
207 var xy = this.tracker.getXY('point'),
208 gridSection = this.headerCt.up('[scrollerOwner]'),
209 rhsMarker = gridSection.getRhsMarker(),
210 el = rhsMarker.parent(),
211 topLeft = el.translatePoints(xy),
212 offsetLeft = el.getLeft(true);
214 rhsMarker.setLeft(topLeft.left - offsetLeft);
215 // Resize as user interacts
222 this.headerCt.dragging = false;
225 var dragHd = this.dragHd,
226 gridSection = this.headerCt.up('[scrollerOwner]'),
227 lhsMarker = gridSection.getLhsMarker(),
228 rhsMarker = gridSection.getRhsMarker(),
229 currWidth = dragHd.getWidth(),
230 offset = this.tracker.getOffset('point'),
234 lhsMarker.setLeft(offscreen);
235 rhsMarker.setLeft(offscreen);
241 doResize: function() {
243 var dragHd = this.dragHd,
245 offset = this.tracker.getOffset('point');
252 this.headerCt.suspendLayout = true;
253 dragHd.setWidth(this.origWidth + offset[0], false);
255 // In the case of forceFit, change the following Header width.
256 // Then apply the two width changes by laying out the owning HeaderContainer
257 // If HeaderContainer is configured forceFit, inhibit upstream layout notification, so that
258 // we can also shrink the following Header by an equal amount, and *then* inform the upstream layout.
259 if (this.headerCt.forceFit) {
260 nextHd = dragHd.nextNode('gridcolumn:not([hidden]):not([isGroupHeader])');
263 nextHd.setWidth(nextHd.getWidth() - offset[0], false);
266 this.headerCt.suspendLayout = false;
267 this.headerCt.doComponentLayout(this.headerCt.getFullWidth());
271 disable: function() {
272 this.disabled = true;
274 this.tracker.disable();
279 this.disabled = false;
281 this.tracker.enable();