Roo/bootstrap/SplitBar.js
[roojs1] / Roo / bootstrap / SplitBar.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11
12
13 /**
14  * @class Roo.bootstrap.SplitBar
15  * @extends Roo.util.Observable
16  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
17  * <br><br>
18  * Usage:
19  * <pre><code>
20 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
21                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
22 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
23 split.minSize = 100;
24 split.maxSize = 600;
25 split.animate = true;
26 split.on('moved', splitterMoved);
27 </code></pre>
28  * @constructor
29  * Create a new SplitBar
30  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
31  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
32  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
34                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
35                         position of the SplitBar).
36  */
37 Roo.bootstrap.SplitBar = function(cfg){
38     
39     /** @private */
40     
41     {   dragElement : elm
42         resizingElement: el,
43         // optional..
44         orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
45         placement : Roo.bootstrap.SplitBar.LEFT  ,
46         // existingProxy ???
47     }
48     
49     this.el = Roo.get(cfg.dragElement, true);
50     this.el.dom.unselectable = "on";
51     /** @private */
52     this.resizingEl = Roo.get(cfg resizingElement, true);
53
54     /**
55      * @private
56      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
57      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
58      * @type Number
59      */
60     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
61     
62     /**
63      * The minimum size of the resizing element. (Defaults to 0)
64      * @type Number
65      */
66     this.minSize = 0;
67     
68     /**
69      * The maximum size of the resizing element. (Defaults to 2000)
70      * @type Number
71      */
72     this.maxSize = 2000;
73     
74     /**
75      * Whether to animate the transition to the new size
76      * @type Boolean
77      */
78     this.animate = false;
79     
80     /**
81      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
82      * @type Boolean
83      */
84     this.useShim = false;
85     
86     /** @private */
87     this.shim = null;
88     
89     if(!cfg.existingProxy){
90         /** @private */
91         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
92     }else{
93         this.proxy = Roo.get(cfg.existingProxy).dom;
94     }
95     /** @private */
96     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
97     
98     /** @private */
99     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
100     
101     /** @private */
102     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
103     
104     /** @private */
105     this.dragSpecs = {};
106     
107     /**
108      * @private The adapter to use to positon and resize elements
109      */
110     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
111     this.adapter.init(this);
112     
113     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
114         /** @private */
115         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
116         this.el.addClass("x-splitbar-h");
117     }else{
118         /** @private */
119         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
120         this.el.addClass("x-splitbar-v");
121     }
122     
123     this.addEvents({
124         /**
125          * @event resize
126          * Fires when the splitter is moved (alias for {@link #event-moved})
127          * @param {Roo.bootstrap.SplitBar} this
128          * @param {Number} newSize the new width or height
129          */
130         "resize" : true,
131         /**
132          * @event moved
133          * Fires when the splitter is moved
134          * @param {Roo.bootstrap.SplitBar} this
135          * @param {Number} newSize the new width or height
136          */
137         "moved" : true,
138         /**
139          * @event beforeresize
140          * Fires before the splitter is dragged
141          * @param {Roo.bootstrap.SplitBar} this
142          */
143         "beforeresize" : true,
144
145         "beforeapply" : true
146     });
147
148     Roo.util.Observable.call(this);
149 };
150
151 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
152     onStartProxyDrag : function(x, y){
153         this.fireEvent("beforeresize", this);
154         if(!this.overlay){
155             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
156             o.unselectable();
157             o.enableDisplayMode("block");
158             // all splitbars share the same overlay
159             Roo.bootstrap.SplitBar.prototype.overlay = o;
160         }
161         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
162         this.overlay.show();
163         Roo.get(this.proxy).setDisplayed("block");
164         var size = this.adapter.getElementSize(this);
165         this.activeMinSize = this.getMinimumSize();;
166         this.activeMaxSize = this.getMaximumSize();;
167         var c1 = size - this.activeMinSize;
168         var c2 = Math.max(this.activeMaxSize - size, 0);
169         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
170             this.dd.resetConstraints();
171             this.dd.setXConstraint(
172                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
173                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
174             );
175             this.dd.setYConstraint(0, 0);
176         }else{
177             this.dd.resetConstraints();
178             this.dd.setXConstraint(0, 0);
179             this.dd.setYConstraint(
180                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
181                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
182             );
183          }
184         this.dragSpecs.startSize = size;
185         this.dragSpecs.startPoint = [x, y];
186         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
187     },
188     
189     /** 
190      * @private Called after the drag operation by the DDProxy
191      */
192     onEndProxyDrag : function(e){
193         Roo.get(this.proxy).setDisplayed(false);
194         var endPoint = Roo.lib.Event.getXY(e);
195         if(this.overlay){
196             this.overlay.hide();
197         }
198         var newSize;
199         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
200             newSize = this.dragSpecs.startSize + 
201                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
202                     endPoint[0] - this.dragSpecs.startPoint[0] :
203                     this.dragSpecs.startPoint[0] - endPoint[0]
204                 );
205         }else{
206             newSize = this.dragSpecs.startSize + 
207                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
208                     endPoint[1] - this.dragSpecs.startPoint[1] :
209                     this.dragSpecs.startPoint[1] - endPoint[1]
210                 );
211         }
212         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
213         if(newSize != this.dragSpecs.startSize){
214             if(this.fireEvent('beforeapply', this, newSize) !== false){
215                 this.adapter.setElementSize(this, newSize);
216                 this.fireEvent("moved", this, newSize);
217                 this.fireEvent("resize", this, newSize);
218             }
219         }
220     },
221     
222     /**
223      * Get the adapter this SplitBar uses
224      * @return The adapter object
225      */
226     getAdapter : function(){
227         return this.adapter;
228     },
229     
230     /**
231      * Set the adapter this SplitBar uses
232      * @param {Object} adapter A SplitBar adapter object
233      */
234     setAdapter : function(adapter){
235         this.adapter = adapter;
236         this.adapter.init(this);
237     },
238     
239     /**
240      * Gets the minimum size for the resizing element
241      * @return {Number} The minimum size
242      */
243     getMinimumSize : function(){
244         return this.minSize;
245     },
246     
247     /**
248      * Sets the minimum size for the resizing element
249      * @param {Number} minSize The minimum size
250      */
251     setMinimumSize : function(minSize){
252         this.minSize = minSize;
253     },
254     
255     /**
256      * Gets the maximum size for the resizing element
257      * @return {Number} The maximum size
258      */
259     getMaximumSize : function(){
260         return this.maxSize;
261     },
262     
263     /**
264      * Sets the maximum size for the resizing element
265      * @param {Number} maxSize The maximum size
266      */
267     setMaximumSize : function(maxSize){
268         this.maxSize = maxSize;
269     },
270     
271     /**
272      * Sets the initialize size for the resizing element
273      * @param {Number} size The initial size
274      */
275     setCurrentSize : function(size){
276         var oldAnimate = this.animate;
277         this.animate = false;
278         this.adapter.setElementSize(this, size);
279         this.animate = oldAnimate;
280     },
281     
282     /**
283      * Destroy this splitbar. 
284      * @param {Boolean} removeEl True to remove the element
285      */
286     destroy : function(removeEl){
287         if(this.shim){
288             this.shim.remove();
289         }
290         this.dd.unreg();
291         this.proxy.parentNode.removeChild(this.proxy);
292         if(removeEl){
293             this.el.remove();
294         }
295     }
296 });
297
298 /**
299  * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
300  */
301 Roo.bootstrap.SplitBar.createProxy = function(dir){
302     var proxy = new Roo.Element(document.createElement("div"));
303     proxy.unselectable();
304     var cls = 'x-splitbar-proxy';
305     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
306     document.body.appendChild(proxy.dom);
307     return proxy.dom;
308 };
309
310 /** 
311  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
312  * Default Adapter. It assumes the splitter and resizing element are not positioned
313  * elements and only gets/sets the width of the element. Generally used for table based layouts.
314  */
315 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
316 };
317
318 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
319     // do nothing for now
320     init : function(s){
321     
322     },
323     /**
324      * Called before drag operations to get the current size of the resizing element. 
325      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
326      */
327      getElementSize : function(s){
328         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
329             return s.resizingEl.getWidth();
330         }else{
331             return s.resizingEl.getHeight();
332         }
333     },
334     
335     /**
336      * Called after drag operations to set the size of the resizing element.
337      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
338      * @param {Number} newSize The new size to set
339      * @param {Function} onComplete A function to be invoked when resizing is complete
340      */
341     setElementSize : function(s, newSize, onComplete){
342         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
343             if(!s.animate){
344                 s.resizingEl.setWidth(newSize);
345                 if(onComplete){
346                     onComplete(s, newSize);
347                 }
348             }else{
349                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
350             }
351         }else{
352             
353             if(!s.animate){
354                 s.resizingEl.setHeight(newSize);
355                 if(onComplete){
356                     onComplete(s, newSize);
357                 }
358             }else{
359                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
360             }
361         }
362     }
363 };
364
365 /** 
366  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
367  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
368  * Adapter that  moves the splitter element to align with the resized sizing element. 
369  * Used with an absolute positioned SplitBar.
370  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
371  * document.body, make sure you assign an id to the body element.
372  */
373 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
374     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
375     this.container = Roo.get(container);
376 };
377
378 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
379     init : function(s){
380         this.basic.init(s);
381     },
382     
383     getElementSize : function(s){
384         return this.basic.getElementSize(s);
385     },
386     
387     setElementSize : function(s, newSize, onComplete){
388         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
389     },
390     
391     moveSplitter : function(s){
392         var yes = Roo.bootstrap.SplitBar;
393         switch(s.placement){
394             case yes.LEFT:
395                 s.el.setX(s.resizingEl.getRight());
396                 break;
397             case yes.RIGHT:
398                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
399                 break;
400             case yes.TOP:
401                 s.el.setY(s.resizingEl.getBottom());
402                 break;
403             case yes.BOTTOM:
404                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
405                 break;
406         }
407     }
408 };
409
410 /**
411  * Orientation constant - Create a vertical SplitBar
412  * @static
413  * @type Number
414  */
415 Roo.bootstrap.SplitBar.VERTICAL = 1;
416
417 /**
418  * Orientation constant - Create a horizontal SplitBar
419  * @static
420  * @type Number
421  */
422 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
423
424 /**
425  * Placement constant - The resizing element is to the left of the splitter element
426  * @static
427  * @type Number
428  */
429 Roo.bootstrap.SplitBar.LEFT = 1;
430
431 /**
432  * Placement constant - The resizing element is to the right of the splitter element
433  * @static
434  * @type Number
435  */
436 Roo.bootstrap.SplitBar.RIGHT = 2;
437
438 /**
439  * Placement constant - The resizing element is positioned above the splitter element
440  * @static
441  * @type Number
442  */
443 Roo.bootstrap.SplitBar.TOP = 3;
444
445 /**
446  * Placement constant - The resizing element is positioned under splitter element
447  * @static
448  * @type Number
449  */
450 Roo.bootstrap.SplitBar.BOTTOM = 4;