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