Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / HeaderResizer.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-grid.plugin.HeaderResizer'>/**
2 </span> * @class Ext.grid.plugin.HeaderResizer
3  * @extends Ext.util.Observable
4  * 
5  * Plugin to add header resizing functionality to a HeaderContainer.
6  * Always resizing header to the left of the splitter you are resizing.
7  * 
8  * Todo: Consider RTL support, columns would always calculate to the right of
9  *    the splitter instead of to the left.
10  */
11 Ext.define('Ext.grid.plugin.HeaderResizer', {
12     extend: 'Ext.util.Observable',
13     requires: ['Ext.dd.DragTracker', 'Ext.util.Region'],
14     alias: 'plugin.gridheaderresizer',
15     
16     disabled: false,
17
18 <span id='Ext-grid.plugin.HeaderResizer-cfg-dynamic'>    /**
19 </span>     * @cfg {Boolean} dynamic
20      * Set to true to resize on the fly rather than using a proxy marker. Defaults to false.
21      */
22     configs: {
23         dynamic: true
24     },
25
26     colHeaderCls: Ext.baseCSSPrefix + 'column-header',
27
28     minColWidth: 40,
29     maxColWidth: 1000,
30     wResizeCursor: 'col-resize',
31     eResizeCursor: 'col-resize',
32     // not using w and e resize bc we are only ever resizing one
33     // column
34     //wResizeCursor: Ext.isWebKit ? 'w-resize' : 'col-resize',
35     //eResizeCursor: Ext.isWebKit ? 'e-resize' : 'col-resize',
36
37     init: function(headerCt) {
38         this.headerCt = headerCt;
39         headerCt.on('render', this.afterHeaderRender, this, {single: true});
40     },
41
42 <span id='Ext-grid.plugin.HeaderResizer-method-destroy'>    /**
43 </span>     * @private
44      * AbstractComponent calls destroy on all its plugins at destroy time.
45      */
46     destroy: function() {
47         if (this.tracker) {
48             this.tracker.destroy();
49         }
50     },
51
52     afterHeaderRender: function() {
53         var headerCt = this.headerCt,
54             el = headerCt.el;
55
56         headerCt.mon(el, 'mousemove', this.onHeaderCtMouseMove, this);
57
58         this.tracker = Ext.create('Ext.dd.DragTracker', {
59             disabled: this.disabled,
60             onBeforeStart: Ext.Function.bind(this.onBeforeStart, this),
61             onStart: Ext.Function.bind(this.onStart, this),
62             onDrag: Ext.Function.bind(this.onDrag, this),
63             onEnd: Ext.Function.bind(this.onEnd, this),
64             tolerance: 3,
65             autoStart: 300,
66             el: el
67         });
68     },
69
70     // As we mouse over individual headers, change the cursor to indicate
71     // that resizing is available, and cache the resize target header for use
72     // if/when they mousedown.
73     onHeaderCtMouseMove: function(e, t) {
74         if (this.headerCt.dragging) {
75             if (this.activeHd) {
76                 this.activeHd.el.dom.style.cursor = '';
77                 delete this.activeHd;
78             }
79         } else {
80             var headerEl = e.getTarget('.' + this.colHeaderCls, 3, true),
81                 overHeader, resizeHeader;
82
83             if (headerEl){
84                 overHeader = Ext.getCmp(headerEl.id);
85
86                 // On left edge, we are resizing the previous non-hidden, base level column.
87                 if (overHeader.isOnLeftEdge(e)) {
88                     resizeHeader = overHeader.previousNode('gridcolumn:not([hidden]):not([isGroupHeader])');
89                 }
90                 // Else, if on the right edge, we're resizing the column we are over
91                 else if (overHeader.isOnRightEdge(e)) {
92                     resizeHeader = overHeader;
93                 }
94                 // Between the edges: we are not resizing
95                 else {
96                     resizeHeader = null;
97                 }
98
99                 // We *are* resizing
100                 if (resizeHeader) {
101                     // If we're attempting to resize a group header, that cannot be resized,
102                     // so find its last base level column header; Group headers are sized
103                     // by the size of their child headers.
104                     if (resizeHeader.isGroupHeader) {
105                         resizeHeader = resizeHeader.getVisibleGridColumns();
106                         resizeHeader = resizeHeader[resizeHeader.length - 1];
107                     }
108
109                     if (resizeHeader &amp;&amp; !resizeHeader.fixed) {
110                         this.activeHd = resizeHeader;
111                         overHeader.el.dom.style.cursor = this.eResizeCursor;
112                     }
113                 // reset
114                 } else {
115                     overHeader.el.dom.style.cursor = '';
116                     delete this.activeHd;
117                 }
118             }
119         }
120     },
121
122     // only start when there is an activeHd
123     onBeforeStart : function(e){
124         var t = e.getTarget();
125         // cache the activeHd because it will be cleared.
126         this.dragHd = this.activeHd;
127
128         if (!!this.dragHd &amp;&amp; !Ext.fly(t).hasCls('x-column-header-trigger') &amp;&amp; !this.headerCt.dragging) {
129             //this.headerCt.dragging = true;
130             this.tracker.constrainTo = this.getConstrainRegion();
131             return true;
132         } else {
133             this.headerCt.dragging = false;
134             return false;
135         }
136     },
137
138     // get the region to constrain to, takes into account max and min col widths
139     getConstrainRegion: function() {
140         var dragHdEl = this.dragHd.el,
141             region   = Ext.util.Region.getRegion(dragHdEl);
142
143         return region.adjust(
144             0,
145             this.maxColWidth - dragHdEl.getWidth(),
146             0,
147             this.minColWidth
148         );
149     },
150
151     // initialize the left and right hand side markers around
152     // the header that we are resizing
153     onStart: function(e){
154         var me       = this,
155             dragHd   = me.dragHd,
156             dragHdEl = dragHd.el,
157             width    = dragHdEl.getWidth(),
158             headerCt = me.headerCt,
159             t        = e.getTarget();
160
161         if (me.dragHd &amp;&amp; !Ext.fly(t).hasCls('x-column-header-trigger')) {
162             headerCt.dragging = true;
163         }
164
165         me.origWidth = width;
166
167         // setup marker proxies
168         if (!me.dynamic) {
169             var xy           = dragHdEl.getXY(),
170                 gridSection  = headerCt.up('[scrollerOwner]'),
171                 dragHct      = me.dragHd.up(':not([isGroupHeader])'),
172                 firstSection = dragHct.up(),
173                 lhsMarker    = gridSection.getLhsMarker(),
174                 rhsMarker    = gridSection.getRhsMarker(),
175                 el           = rhsMarker.parent(),
176                 offsetLeft   = el.getLeft(true),
177                 offsetTop    = el.getTop(true),
178                 topLeft      = el.translatePoints(xy),
179                 markerHeight = firstSection.body.getHeight() + headerCt.getHeight(),
180                 top = topLeft.top - offsetTop;
181
182             lhsMarker.setTop(top);
183             rhsMarker.setTop(top);
184             lhsMarker.setHeight(markerHeight);
185             rhsMarker.setHeight(markerHeight);
186             lhsMarker.setLeft(topLeft.left - offsetLeft);
187             rhsMarker.setLeft(topLeft.left + width - offsetLeft);
188         }
189     },
190
191     // synchronize the rhsMarker with the mouse movement
192     onDrag: function(e){
193         if (!this.dynamic) {
194             var xy          = this.tracker.getXY('point'),
195                 gridSection = this.headerCt.up('[scrollerOwner]'),
196                 rhsMarker   = gridSection.getRhsMarker(),
197                 el          = rhsMarker.parent(),
198                 topLeft     = el.translatePoints(xy),
199                 offsetLeft  = el.getLeft(true);
200
201             rhsMarker.setLeft(topLeft.left - offsetLeft);
202         // Resize as user interacts
203         } else {
204             this.doResize();
205         }
206     },
207
208     onEnd: function(e){
209         this.headerCt.dragging = false;
210         if (this.dragHd) {
211             if (!this.dynamic) {
212                 var dragHd      = this.dragHd,
213                     gridSection = this.headerCt.up('[scrollerOwner]'),
214                     lhsMarker   = gridSection.getLhsMarker(),
215                     rhsMarker   = gridSection.getRhsMarker(),
216                     currWidth   = dragHd.getWidth(),
217                     offset      = this.tracker.getOffset('point'),
218                     offscreen   = -9999;
219
220                 // hide markers
221                 lhsMarker.setLeft(offscreen);
222                 rhsMarker.setLeft(offscreen);
223             }
224             this.doResize();
225         }
226     },
227
228     doResize: function() {
229         if (this.dragHd) {
230             var dragHd = this.dragHd,
231                 nextHd,
232                 offset = this.tracker.getOffset('point');
233
234             // resize the dragHd
235             if (dragHd.flex) {
236                 delete dragHd.flex;
237             }
238
239             // If HeaderContainer is configured forceFit, inhibit upstream layout notification, so that
240             // we can also shrink the following Header by an equal amount, and *then* inform the upstream layout.
241             if (this.headerCt.forceFit) {
242                 nextHd = dragHd.nextNode('gridcolumn:not([hidden]):not([isGroupHeader])');
243                 if (nextHd) {
244                     this.headerCt.componentLayout.layoutBusy = true;
245                 }
246             }
247
248             // Non-flexed Headers may never be squeezed in the event of a shortfall so
249             // always set the minWidth to their current width.
250             dragHd.minWidth = this.origWidth + offset[0];
251             dragHd.setWidth(dragHd.minWidth);
252
253             // In the case of forceFit, change the following Header width.
254             // Then apply the two width changes by laying out the owning HeaderContainer
255             if (nextHd) {
256                 delete nextHd.flex;
257                 nextHd.setWidth(nextHd.getWidth() - offset[0]);
258                 this.headerCt.componentLayout.layoutBusy = false;
259                 this.headerCt.doComponentLayout();
260             }
261         }
262     },
263     
264     disable: function() {
265         this.disabled = true;
266         if (this.tracker) {
267             this.tracker.disable();
268         }
269     },
270     
271     enable: function() {
272         this.disabled = false;
273         if (this.tracker) {
274             this.tracker.enable();
275         }
276     }
277 });</pre></pre></body></html>