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