Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / resizer / Splitter.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
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.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * This class functions between siblings of a {@link Ext.layout.container.VBox VBox} or {@link Ext.layout.container.HBox HBox}
17  * layout to resize both immediate siblings.
18  *
19  * By default it will set the size of both siblings. <b>One</b> of the siblings may be configured with
20  * `{@link Ext.Component#maintainFlex maintainFlex}: true` which will cause it not to receive a new size explicitly, but to be resized
21  * by the layout.
22  *
23  * A Splitter may be configured to show a centered mini-collapse tool orientated to collapse the {@link #collapseTarget}.
24  * The Splitter will then call that sibling Panel's {@link Ext.panel.Panel#collapse collapse} or {@link Ext.panel.Panel#expand expand} method
25  * to perform the appropriate operation (depending on the sibling collapse state). To create the mini-collapse tool but take care
26  * of collapsing yourself, configure the splitter with <code>{@link #performCollapse} false</code>.
27  */
28 Ext.define('Ext.resizer.Splitter', {
29     extend: 'Ext.Component',
30     requires: ['Ext.XTemplate'],
31     uses: ['Ext.resizer.SplitterTracker'],
32     alias: 'widget.splitter',
33
34     renderTpl: [
35         '<tpl if="collapsible===true">',
36             '<div id="{id}-collapseEl" class="', Ext.baseCSSPrefix, 'collapse-el ',
37                     Ext.baseCSSPrefix, 'layout-split-{collapseDir}">&nbsp;</div>',
38         '</tpl>'
39     ],
40
41     baseCls: Ext.baseCSSPrefix + 'splitter',
42     collapsedClsInternal: Ext.baseCSSPrefix + 'splitter-collapsed',
43
44     /**
45      * @cfg {Boolean} collapsible
46      * <code>true</code> to show a mini-collapse tool in the Splitter to toggle expand and collapse on the {@link #collapseTarget} Panel.
47      * Defaults to the {@link Ext.panel.Panel#collapsible collapsible} setting of the Panel.
48      */
49     collapsible: false,
50
51     /**
52      * @cfg {Boolean} performCollapse
53      * <p>Set to <code>false</code> to prevent this Splitter's mini-collapse tool from managing the collapse
54      * state of the {@link #collapseTarget}.</p>
55      */
56
57     /**
58      * @cfg {Boolean} collapseOnDblClick
59      * <code>true</code> to enable dblclick to toggle expand and collapse on the {@link #collapseTarget} Panel.
60      */
61     collapseOnDblClick: true,
62
63     /**
64      * @cfg {Number} defaultSplitMin
65      * Provides a default minimum width or height for the two components
66      * that the splitter is between.
67      */
68     defaultSplitMin: 40,
69
70     /**
71      * @cfg {Number} defaultSplitMax
72      * Provides a default maximum width or height for the two components
73      * that the splitter is between.
74      */
75     defaultSplitMax: 1000,
76
77     /**
78      * @cfg {String} collapsedCls
79      * A class to add to the splitter when it is collapsed. See {@link #collapsible}.
80      */
81
82     width: 5,
83     height: 5,
84
85     /**
86      * @cfg {String/Ext.panel.Panel} collapseTarget
87      * <p>A string describing the relative position of the immediate sibling Panel to collapse. May be 'prev' or 'next' (Defaults to 'next')</p>
88      * <p>Or the immediate sibling Panel to collapse.</p>
89      * <p>The orientation of the mini-collapse tool will be inferred from this setting.</p>
90      * <p><b>Note that only Panels may be collapsed.</b></p>
91      */
92     collapseTarget: 'next',
93
94     /**
95      * @property orientation
96      * @type String
97      * Orientation of this Splitter. <code>'vertical'</code> when used in an hbox layout, <code>'horizontal'</code>
98      * when used in a vbox layout.
99      */
100
101     onRender: function() {
102         var me = this,
103             target = me.getCollapseTarget(),
104             collapseDir = me.getCollapseDirection();
105
106         Ext.applyIf(me.renderData, {
107             collapseDir: collapseDir,
108             collapsible: me.collapsible || target.collapsible
109         });
110
111         me.addChildEls('collapseEl');
112
113         this.callParent(arguments);
114
115         // Add listeners on the mini-collapse tool unless performCollapse is set to false
116         if (me.performCollapse !== false) {
117             if (me.renderData.collapsible) {
118                 me.mon(me.collapseEl, 'click', me.toggleTargetCmp, me);
119             }
120             if (me.collapseOnDblClick) {
121                 me.mon(me.el, 'dblclick', me.toggleTargetCmp, me);
122             }
123         }
124
125         // Ensure the mini collapse icon is set to the correct direction when the target is collapsed/expanded by any means
126         me.mon(target, 'collapse', me.onTargetCollapse, me);
127         me.mon(target, 'expand', me.onTargetExpand, me);
128
129         me.el.addCls(me.baseCls + '-' + me.orientation);
130         me.el.unselectable();
131
132         me.tracker = Ext.create('Ext.resizer.SplitterTracker', {
133             el: me.el
134         });
135
136         // Relay the most important events to our owner (could open wider later):
137         me.relayEvents(me.tracker, [ 'beforedragstart', 'dragstart', 'dragend' ]);
138     },
139
140     getCollapseDirection: function() {
141         var me = this,
142             idx,
143             type = me.ownerCt.layout.type;
144
145         // Avoid duplication of string tests.
146         // Create a two bit truth table of the configuration of the Splitter:
147         // Collapse Target | orientation
148         //        0              0             = next, horizontal
149         //        0              1             = next, vertical
150         //        1              0             = prev, horizontal
151         //        1              1             = prev, vertical
152         if (me.collapseTarget.isComponent) {
153             idx = Number(me.ownerCt.items.indexOf(me.collapseTarget) == me.ownerCt.items.indexOf(me) - 1) << 1 | Number(type == 'hbox');
154         } else {
155             idx = Number(me.collapseTarget == 'prev') << 1 | Number(type == 'hbox');
156         }
157
158         // Read the data out the truth table
159         me.orientation = ['horizontal', 'vertical'][idx & 1];
160         return ['bottom', 'right', 'top', 'left'][idx];
161     },
162
163     getCollapseTarget: function() {
164         var me = this;
165
166         return me.collapseTarget.isComponent ? me.collapseTarget : me.collapseTarget == 'prev' ? me.previousSibling() : me.nextSibling();
167     },
168
169     onTargetCollapse: function(target) {
170         this.el.addCls([this.collapsedClsInternal, this.collapsedCls]);
171     },
172
173     onTargetExpand: function(target) {
174         this.el.removeCls([this.collapsedClsInternal, this.collapsedCls]);
175     },
176
177     toggleTargetCmp: function(e, t) {
178         var cmp = this.getCollapseTarget();
179
180         if (cmp.isVisible()) {
181             // restore
182             if (cmp.collapsed) {
183                 cmp.expand(cmp.animCollapse);
184             // collapse
185             } else {
186                 cmp.collapse(this.renderData.collapseDir, cmp.animCollapse);
187             }
188         }
189     },
190
191     /*
192      * Work around IE bug. %age margins do not get recalculated on element resize unless repaint called.
193      */
194     setSize: function() {
195         var me = this;
196         me.callParent(arguments);
197         if (Ext.isIE) {
198             me.el.repaint();
199         }
200     }
201 });
202