Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / docs / source / SplitterTracker.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-resizer-SplitterTracker'>/**
19 </span> * @class Ext.resizer.SplitterTracker
20  * @extends Ext.dd.DragTracker
21  * Private utility class for Ext.Splitter.
22  * @private
23  */
24 Ext.define('Ext.resizer.SplitterTracker', {
25     extend: 'Ext.dd.DragTracker',
26     requires: ['Ext.util.Region'],
27     enabled: true,
28     
29     overlayCls: Ext.baseCSSPrefix + 'resizable-overlay',
30
31     getPrevCmp: function() {
32         var splitter = this.getSplitter();
33         return splitter.previousSibling();
34     },
35
36     getNextCmp: function() {
37         var splitter = this.getSplitter();
38         return splitter.nextSibling();
39     },
40
41     // ensure the tracker is enabled, store boxes of previous and next
42     // components and calculate the constrain region
43     onBeforeStart: function(e) {
44         var me = this,
45             prevCmp = me.getPrevCmp(),
46             nextCmp = me.getNextCmp(),
47             collapseEl = me.getSplitter().collapseEl,
48             overlay;
49             
50         if (collapseEl &amp;&amp; (e.getTarget() === me.getSplitter().collapseEl.dom)) {
51             return false;
52         }
53
54         // SplitterTracker is disabled if any of its adjacents are collapsed.
55         if (nextCmp.collapsed || prevCmp.collapsed) {
56             return false;
57         }
58         
59         overlay = me.overlay =  Ext.getBody().createChild({
60             cls: me.overlayCls, 
61             html: '&amp;#160;'
62         });
63         overlay.unselectable();
64         overlay.setSize(Ext.core.Element.getViewWidth(true), Ext.core.Element.getViewHeight(true));
65         overlay.show();
66         
67         // store boxes of previous and next
68         me.prevBox  = prevCmp.getEl().getBox();
69         me.nextBox  = nextCmp.getEl().getBox();
70         me.constrainTo = me.calculateConstrainRegion();
71     },
72
73     // We move the splitter el. Add the proxy class.
74     onStart: function(e) {
75         var splitter = this.getSplitter();
76         splitter.addCls(splitter.baseCls + '-active');
77     },
78
79     // calculate the constrain Region in which the splitter el may be moved.
80     calculateConstrainRegion: function() {
81         var me         = this,
82             splitter   = me.getSplitter(),
83             splitWidth = splitter.getWidth(),
84             defaultMin = splitter.defaultSplitMin,
85             orient     = splitter.orientation,
86             prevBox    = me.prevBox,
87             prevCmp    = me.getPrevCmp(),
88             nextBox    = me.nextBox,
89             nextCmp    = me.getNextCmp(),
90             // prev and nextConstrainRegions are the maximumBoxes minus the
91             // minimumBoxes. The result is always the intersection
92             // of these two boxes.
93             prevConstrainRegion, nextConstrainRegion;
94
95         // vertical splitters, so resizing left to right
96         if (orient === 'vertical') {
97
98             // Region constructor accepts (top, right, bottom, left)
99             // anchored/calculated from the left
100             prevConstrainRegion = Ext.create('Ext.util.Region',
101                 prevBox.y,
102                 // Right boundary is x + maxWidth if there IS a maxWidth.
103                 // Otherwise it is calculated based upon the minWidth of the next Component
104                 (prevCmp.maxWidth ? prevBox.x + prevCmp.maxWidth : nextBox.right - (nextCmp.minWidth || defaultMin)) + splitWidth,
105                 prevBox.bottom,
106                 prevBox.x + (prevCmp.minWidth || defaultMin)
107             );
108             // anchored/calculated from the right
109             nextConstrainRegion = Ext.create('Ext.util.Region',
110                 nextBox.y,
111                 nextBox.right - (nextCmp.minWidth || defaultMin),
112                 nextBox.bottom,
113                 // Left boundary is right - maxWidth if there IS a maxWidth.
114                 // Otherwise it is calculated based upon the minWidth of the previous Component
115                 (nextCmp.maxWidth ? nextBox.right - nextCmp.maxWidth : prevBox.x + (prevBox.minWidth || defaultMin)) - splitWidth
116             );
117         } else {
118             // anchored/calculated from the top
119             prevConstrainRegion = Ext.create('Ext.util.Region',
120                 prevBox.y + (prevCmp.minHeight || defaultMin),
121                 prevBox.right,
122                 // Bottom boundary is y + maxHeight if there IS a maxHeight.
123                 // Otherwise it is calculated based upon the minWidth of the next Component
124                 (prevCmp.maxHeight ? prevBox.y + prevCmp.maxHeight : nextBox.bottom - (nextCmp.minHeight || defaultMin)) + splitWidth,
125                 prevBox.x
126             );
127             // anchored/calculated from the bottom
128             nextConstrainRegion = Ext.create('Ext.util.Region',
129                 // Top boundary is bottom - maxHeight if there IS a maxHeight.
130                 // Otherwise it is calculated based upon the minHeight of the previous Component
131                 (nextCmp.maxHeight ? nextBox.bottom - nextCmp.maxHeight : prevBox.y + (prevCmp.minHeight || defaultMin)) - splitWidth,
132                 nextBox.right,
133                 nextBox.bottom - (nextCmp.minHeight || defaultMin),
134                 nextBox.x
135             );
136         }
137
138         // intersection of the two regions to provide region draggable
139         return prevConstrainRegion.intersect(nextConstrainRegion);
140     },
141
142     // Performs the actual resizing of the previous and next components
143     performResize: function(e) {
144         var me       = this,
145             offset   = me.getOffset('dragTarget'),
146             splitter = me.getSplitter(),
147             orient   = splitter.orientation,
148             prevCmp  = me.getPrevCmp(),
149             nextCmp  = me.getNextCmp(),
150             owner    = splitter.ownerCt,
151             layout   = owner.getLayout();
152
153         // Inhibit automatic container layout caused by setSize calls below.
154         owner.suspendLayout = true;
155
156         if (orient === 'vertical') {
157             if (prevCmp) {
158                 if (!prevCmp.maintainFlex) {
159                     delete prevCmp.flex;
160                     prevCmp.setSize(me.prevBox.width + offset[0], prevCmp.getHeight());
161                 }
162             }
163             if (nextCmp) {
164                 if (!nextCmp.maintainFlex) {
165                     delete nextCmp.flex;
166                     nextCmp.setSize(me.nextBox.width - offset[0], nextCmp.getHeight());
167                 }
168             }
169         // verticals
170         } else {
171             if (prevCmp) {
172                 if (!prevCmp.maintainFlex) {
173                     delete prevCmp.flex;
174                     prevCmp.setSize(prevCmp.getWidth(), me.prevBox.height + offset[1]);
175                 }
176             }
177             if (nextCmp) {
178                 if (!nextCmp.maintainFlex) {
179                     delete nextCmp.flex;
180                     nextCmp.setSize(prevCmp.getWidth(), me.nextBox.height - offset[1]);
181                 }
182             }
183         }
184         delete owner.suspendLayout;
185         layout.onLayout();
186     },
187
188     // Cleans up the overlay (if we have one) and calls the base. This cannot be done in
189     // onEnd, because onEnd is only called if a drag is detected but the overlay is created
190     // regardless (by onBeforeStart).
191     endDrag: function () {
192         var me = this;
193
194         if (me.overlay) {
195              me.overlay.remove();
196              delete me.overlay;
197         }
198
199         me.callParent(arguments); // this calls onEnd
200     },
201
202     // perform the resize and remove the proxy class from the splitter el
203     onEnd: function(e) {
204         var me = this,
205             splitter = me.getSplitter();
206             
207         splitter.removeCls(splitter.baseCls + '-active');
208         me.performResize();
209     },
210
211     // Track the proxy and set the proper XY coordinates
212     // while constraining the drag
213     onDrag: function(e) {
214         var me        = this,
215             offset    = me.getOffset('dragTarget'),
216             splitter  = me.getSplitter(),
217             splitEl   = splitter.getEl(),
218             orient    = splitter.orientation;
219
220         if (orient === &quot;vertical&quot;) {
221             splitEl.setX(me.startRegion.left + offset[0]);
222         } else {
223             splitEl.setY(me.startRegion.top + offset[1]);
224         }
225     },
226
227     getSplitter: function() {
228         return Ext.getCmp(this.getDragCt().id);
229     }
230 });</pre>
231 </body>
232 </html>