source: trunk/web/addons/job_monarch/lib/extjs-30/pkgs/resizable-debug.js @ 625

Last change on this file since 625 was 625, checked in by ramonb, 15 years ago

lib/extjs-30:

  • new ExtJS 3.0
File size: 25.1 KB
Line 
1/*!
2 * Ext JS Library 3.0.0
3 * Copyright(c) 2006-2009 Ext JS, LLC
4 * licensing@extjs.com
5 * http://www.extjs.com/license
6 */
7/**
8 * @class Ext.Resizable
9 * @extends Ext.util.Observable
10 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
11 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
12 * the textarea in a div and set 'resizeChild' to true (or to the id of the element), <b>or</b> set wrap:true in your config and
13 * the element will be wrapped for you automatically.</p>
14 * <p>Here is the list of valid resize handles:</p>
15 * <pre>
16Value   Description
17------  -------------------
18 'n'     north
19 's'     south
20 'e'     east
21 'w'     west
22 'nw'    northwest
23 'sw'    southwest
24 'se'    southeast
25 'ne'    northeast
26 'all'   all
27</pre>
28 * <p>Here's an example showing the creation of a typical Resizable:</p>
29 * <pre><code>
30var resizer = new Ext.Resizable('element-id', {
31    handles: 'all',
32    minWidth: 200,
33    minHeight: 100,
34    maxWidth: 500,
35    maxHeight: 400,
36    pinned: true
37});
38resizer.on('resize', myHandler);
39</code></pre>
40 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
41 * resizer.east.setDisplayed(false);</p>
42 * @constructor
43 * Create a new resizable component
44 * @param {Mixed} el The id or element to resize
45 * @param {Object} config configuration options
46  */
47Ext.Resizable = function(el, config){
48    this.el = Ext.get(el);
49   
50    if(config && config.wrap){
51        config.resizeChild = this.el;
52        this.el = this.el.wrap(typeof config.wrap == 'object' ? config.wrap : {cls:'xresizable-wrap'});
53        this.el.id = this.el.dom.id = config.resizeChild.id + '-rzwrap';
54        this.el.setStyle('overflow', 'hidden');
55        this.el.setPositioning(config.resizeChild.getPositioning());
56        config.resizeChild.clearPositioning();
57        if(!config.width || !config.height){
58            var csize = config.resizeChild.getSize();
59            this.el.setSize(csize.width, csize.height);
60        }
61        if(config.pinned && !config.adjustments){
62            config.adjustments = 'auto';
63        }
64    }
65
66    /**
67     * The proxy Element that is resized in place of the real Element during the resize operation.
68     * This may be queried using {@link Ext.Element#getBox} to provide the new area to resize to.
69     * Read only.
70     * @type Ext.Element.
71     * @property proxy
72     */
73    this.proxy = this.el.createProxy({tag: 'div', cls: 'x-resizable-proxy', id: this.el.id + '-rzproxy'}, Ext.getBody());
74    this.proxy.unselectable();
75    this.proxy.enableDisplayMode('block');
76
77    Ext.apply(this, config);
78   
79    if(this.pinned){
80        this.disableTrackOver = true;
81        this.el.addClass('x-resizable-pinned');
82    }
83    // if the element isn't positioned, make it relative
84    var position = this.el.getStyle('position');
85    if(position != 'absolute' && position != 'fixed'){
86        this.el.setStyle('position', 'relative');
87    }
88    if(!this.handles){ // no handles passed, must be legacy style
89        this.handles = 's,e,se';
90        if(this.multiDirectional){
91            this.handles += ',n,w';
92        }
93    }
94    if(this.handles == 'all'){
95        this.handles = 'n s e w ne nw se sw';
96    }
97    var hs = this.handles.split(/\s*?[,;]\s*?| /);
98    var ps = Ext.Resizable.positions;
99    for(var i = 0, len = hs.length; i < len; i++){
100        if(hs[i] && ps[hs[i]]){
101            var pos = ps[hs[i]];
102            this[pos] = new Ext.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
103        }
104    }
105    // legacy
106    this.corner = this.southeast;
107   
108    if(this.handles.indexOf('n') != -1 || this.handles.indexOf('w') != -1){
109        this.updateBox = true;
110    }   
111   
112    this.activeHandle = null;
113   
114    if(this.resizeChild){
115        if(typeof this.resizeChild == 'boolean'){
116            this.resizeChild = Ext.get(this.el.dom.firstChild, true);
117        }else{
118            this.resizeChild = Ext.get(this.resizeChild, true);
119        }
120    }
121   
122    if(this.adjustments == 'auto'){
123        var rc = this.resizeChild;
124        var hw = this.west, he = this.east, hn = this.north, hs = this.south;
125        if(rc && (hw || hn)){
126            rc.position('relative');
127            rc.setLeft(hw ? hw.el.getWidth() : 0);
128            rc.setTop(hn ? hn.el.getHeight() : 0);
129        }
130        this.adjustments = [
131            (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
132            (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1 
133        ];
134    }
135   
136    if(this.draggable){
137        this.dd = this.dynamic ? 
138            this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
139        this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
140    }
141   
142    this.addEvents(
143        /**
144         * @event beforeresize
145         * Fired before resize is allowed. Set {@link #enabled} to false to cancel resize.
146         * @param {Ext.Resizable} this
147         * @param {Ext.EventObject} e The mousedown event
148         */
149        'beforeresize',
150        /**
151         * @event resize
152         * Fired after a resize.
153         * @param {Ext.Resizable} this
154         * @param {Number} width The new width
155         * @param {Number} height The new height
156         * @param {Ext.EventObject} e The mouseup event
157         */
158        'resize'
159    );
160   
161    if(this.width !== null && this.height !== null){
162        this.resizeTo(this.width, this.height);
163    }else{
164        this.updateChildSize();
165    }
166    if(Ext.isIE){
167        this.el.dom.style.zoom = 1;
168    }
169    Ext.Resizable.superclass.constructor.call(this);
170};
171
172Ext.extend(Ext.Resizable, Ext.util.Observable, {
173
174    /**
175     * @cfg {Array/String} adjustments String 'auto' or an array [width, height] with values to be <b>added</b> to the
176     * resize operation's new size (defaults to <tt>[0, 0]</tt>)
177     */
178    adjustments : [0, 0],
179    /**
180     * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
181     */
182    animate : false,
183    /**
184     * @cfg {Mixed} constrainTo Constrain the resize to a particular element
185     */
186    /**
187     * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
188     */
189    disableTrackOver : false,
190    /**
191     * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
192     */
193    draggable: false,
194    /**
195     * @cfg {Number} duration Animation duration if animate = true (defaults to 0.35)
196     */
197    duration : 0.35,
198    /**
199     * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
200     */
201    dynamic : false,
202    /**
203     * @cfg {String} easing Animation easing if animate = true (defaults to <tt>'easingOutStrong'</tt>)
204     */
205    easing : 'easeOutStrong',
206    /**
207     * @cfg {Boolean} enabled False to disable resizing (defaults to true)
208     */
209    enabled : true,
210    /**
211     * @property enabled Writable. False if resizing is disabled.
212     * @type Boolean
213     */
214    /**
215     * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined).
216     * Specify either <tt>'all'</tt> or any of <tt>'n s e w ne nw se sw'</tt>.
217     */
218    handles : false,
219    /**
220     * @cfg {Boolean} multiDirectional <b>Deprecated</b>.  Deprecated style of adding multi-direction resize handles.
221     */
222    multiDirectional : false,
223    /**
224     * @cfg {Number} height The height of the element in pixels (defaults to null)
225     */
226    height : null,
227    /**
228     * @cfg {Number} width The width of the element in pixels (defaults to null)
229     */
230    width : null,
231    /**
232     * @cfg {Number} heightIncrement The increment to snap the height resize in pixels
233     * (only applies if <code>{@link #dynamic}==true</code>). Defaults to <tt>0</tt>.
234     */
235    heightIncrement : 0,
236    /**
237     * @cfg {Number} widthIncrement The increment to snap the width resize in pixels
238     * (only applies if <code>{@link #dynamic}==true</code>). Defaults to <tt>0</tt>.
239     */
240    widthIncrement : 0,
241    /**
242     * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
243     */
244    minHeight : 5,
245    /**
246     * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
247     */
248    minWidth : 5,
249    /**
250     * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
251     */
252    maxHeight : 10000,
253    /**
254     * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
255     */
256    maxWidth : 10000,
257    /**
258     * @cfg {Number} minX The minimum x for the element (defaults to 0)
259     */
260    minX: 0,
261    /**
262     * @cfg {Number} minY The minimum x for the element (defaults to 0)
263     */
264    minY: 0,
265    /**
266     * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
267     * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
268     */
269    pinned : false,
270    /**
271     * @cfg {Boolean} preserveRatio True to preserve the original ratio between height
272     * and width during resize (defaults to false)
273     */
274    preserveRatio : false,
275    /**
276     * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
277     */ 
278    resizeChild : false,
279    /**
280     * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
281     */
282    transparent: false,
283    /**
284     * @cfg {Ext.lib.Region} resizeRegion Constrain the resize to a particular region
285     */
286    /**
287     * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
288     * in favor of the handles config option (defaults to false)
289     */
290
291   
292    /**
293     * Perform a manual resize and fires the 'resize' event.
294     * @param {Number} width
295     * @param {Number} height
296     */
297    resizeTo : function(width, height){
298        this.el.setSize(width, height);
299        this.updateChildSize();
300        this.fireEvent('resize', this, width, height, null);
301    },
302
303    // private
304    startSizing : function(e, handle){
305        this.fireEvent('beforeresize', this, e);
306        if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
307
308            if(!this.overlay){
309                this.overlay = this.el.createProxy({tag: 'div', cls: 'x-resizable-overlay', html: '&#160;'}, Ext.getBody());
310                this.overlay.unselectable();
311                this.overlay.enableDisplayMode('block');
312                this.overlay.on({
313                    scope: this,
314                    mousemove: this.onMouseMove,
315                    mouseup: this.onMouseUp
316                });
317            }
318            this.overlay.setStyle('cursor', handle.el.getStyle('cursor'));
319
320            this.resizing = true;
321            this.startBox = this.el.getBox();
322            this.startPoint = e.getXY();
323            this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
324                            (this.startBox.y + this.startBox.height) - this.startPoint[1]];
325
326            this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
327            this.overlay.show();
328
329            if(this.constrainTo) {
330                var ct = Ext.get(this.constrainTo);
331                this.resizeRegion = ct.getRegion().adjust(
332                    ct.getFrameWidth('t'),
333                    ct.getFrameWidth('l'),
334                    -ct.getFrameWidth('b'),
335                    -ct.getFrameWidth('r')
336                );
337            }
338
339            this.proxy.setStyle('visibility', 'hidden'); // workaround display none
340            this.proxy.show();
341            this.proxy.setBox(this.startBox);
342            if(!this.dynamic){
343                this.proxy.setStyle('visibility', 'visible');
344            }
345        }
346    },
347
348    // private
349    onMouseDown : function(handle, e){
350        if(this.enabled){
351            e.stopEvent();
352            this.activeHandle = handle;
353            this.startSizing(e, handle);
354        }         
355    },
356
357    // private
358    onMouseUp : function(e){
359        this.activeHandle = null;
360        var size = this.resizeElement();
361        this.resizing = false;
362        this.handleOut();
363        this.overlay.hide();
364        this.proxy.hide();
365        this.fireEvent('resize', this, size.width, size.height, e);
366    },
367
368    // private
369    updateChildSize : function(){
370        if(this.resizeChild){
371            var el = this.el;
372            var child = this.resizeChild;
373            var adj = this.adjustments;
374            if(el.dom.offsetWidth){
375                var b = el.getSize(true);
376                child.setSize(b.width+adj[0], b.height+adj[1]);
377            }
378            // Second call here for IE
379            // The first call enables instant resizing and
380            // the second call corrects scroll bars if they
381            // exist
382            if(Ext.isIE){
383                setTimeout(function(){
384                    if(el.dom.offsetWidth){
385                        var b = el.getSize(true);
386                        child.setSize(b.width+adj[0], b.height+adj[1]);
387                    }
388                }, 10);
389            }
390        }
391    },
392
393    // private
394    snap : function(value, inc, min){
395        if(!inc || !value){
396            return value;
397        }
398        var newValue = value;
399        var m = value % inc;
400        if(m > 0){
401            if(m > (inc/2)){
402                newValue = value + (inc-m);
403            }else{
404                newValue = value - m;
405            }
406        }
407        return Math.max(min, newValue);
408    },
409
410    /**
411     * <p>Performs resizing of the associated Element. This method is called internally by this
412     * class, and should not be called by user code.</p>
413     * <p>If a Resizable is being used to resize an Element which encapsulates a more complex UI
414     * component such as a Panel, this method may be overridden by specifying an implementation
415     * as a config option to provide appropriate behaviour at the end of the resize operation on
416     * mouseup, for example resizing the Panel, and relaying the Panel's content.</p>
417     * <p>The new area to be resized to is available by examining the state of the {@link #proxy}
418     * Element. Example:
419<pre><code>
420new Ext.Panel({
421    title: 'Resize me',
422    x: 100,
423    y: 100,
424    renderTo: Ext.getBody(),
425    floating: true,
426    frame: true,
427    width: 400,
428    height: 200,
429    listeners: {
430        render: function(p) {
431            new Ext.Resizable(p.getEl(), {
432                handles: 'all',
433                pinned: true,
434                transparent: true,
435                resizeElement: function() {
436                    var box = this.proxy.getBox();
437                    p.updateBox(box);
438                    if (p.layout) {
439                        p.doLayout();
440                    }
441                    return box;
442                }
443           });
444       }
445    }
446}).show();
447</code></pre>
448     */
449    resizeElement : function(){
450        var box = this.proxy.getBox();
451        if(this.updateBox){
452            this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
453        }else{
454            this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
455        }
456        this.updateChildSize();
457        if(!this.dynamic){
458            this.proxy.hide();
459        }
460        return box;
461    },
462
463    // private
464    constrain : function(v, diff, m, mx){
465        if(v - diff < m){
466            diff = v - m;   
467        }else if(v - diff > mx){
468            diff = v - mx; 
469        }
470        return diff;               
471    },
472
473    // private
474    onMouseMove : function(e){
475        if(this.enabled && this.activeHandle){
476            try{// try catch so if something goes wrong the user doesn't get hung
477
478            if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
479                return;
480            }
481
482            //var curXY = this.startPoint;
483            var curSize = this.curSize || this.startBox,
484                x = this.startBox.x, y = this.startBox.y,
485                ox = x, 
486                oy = y,
487                w = curSize.width, 
488                h = curSize.height,
489                ow = w, 
490                oh = h,
491                mw = this.minWidth, 
492                mh = this.minHeight,
493                mxw = this.maxWidth, 
494                mxh = this.maxHeight,
495                wi = this.widthIncrement,
496                hi = this.heightIncrement,
497                eventXY = e.getXY(),
498                diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0])),
499                diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1])),
500                pos = this.activeHandle.position,
501                tw,
502                th;
503           
504            switch(pos){
505                case 'east':
506                    w += diffX; 
507                    w = Math.min(Math.max(mw, w), mxw);
508                    break;
509                case 'south':
510                    h += diffY;
511                    h = Math.min(Math.max(mh, h), mxh);
512                    break;
513                case 'southeast':
514                    w += diffX; 
515                    h += diffY;
516                    w = Math.min(Math.max(mw, w), mxw);
517                    h = Math.min(Math.max(mh, h), mxh);
518                    break;
519                case 'north':
520                    diffY = this.constrain(h, diffY, mh, mxh);
521                    y += diffY;
522                    h -= diffY;
523                    break;
524                case 'west':
525                    diffX = this.constrain(w, diffX, mw, mxw);
526                    x += diffX;
527                    w -= diffX;
528                    break;
529                case 'northeast':
530                    w += diffX; 
531                    w = Math.min(Math.max(mw, w), mxw);
532                    diffY = this.constrain(h, diffY, mh, mxh);
533                    y += diffY;
534                    h -= diffY;
535                    break;
536                case 'northwest':
537                    diffX = this.constrain(w, diffX, mw, mxw);
538                    diffY = this.constrain(h, diffY, mh, mxh);
539                    y += diffY;
540                    h -= diffY;
541                    x += diffX;
542                    w -= diffX;
543                    break;
544               case 'southwest':
545                    diffX = this.constrain(w, diffX, mw, mxw);
546                    h += diffY;
547                    h = Math.min(Math.max(mh, h), mxh);
548                    x += diffX;
549                    w -= diffX;
550                    break;
551            }
552           
553            var sw = this.snap(w, wi, mw);
554            var sh = this.snap(h, hi, mh);
555            if(sw != w || sh != h){
556                switch(pos){
557                    case 'northeast':
558                        y -= sh - h;
559                    break;
560                    case 'north':
561                        y -= sh - h;
562                        break;
563                    case 'southwest':
564                        x -= sw - w;
565                    break;
566                    case 'west':
567                        x -= sw - w;
568                        break;
569                    case 'northwest':
570                        x -= sw - w;
571                        y -= sh - h;
572                    break;
573                }
574                w = sw;
575                h = sh;
576            }
577           
578            if(this.preserveRatio){
579                switch(pos){
580                    case 'southeast':
581                    case 'east':
582                        h = oh * (w/ow);
583                        h = Math.min(Math.max(mh, h), mxh);
584                        w = ow * (h/oh);
585                       break;
586                    case 'south':
587                        w = ow * (h/oh);
588                        w = Math.min(Math.max(mw, w), mxw);
589                        h = oh * (w/ow);
590                        break;
591                    case 'northeast':
592                        w = ow * (h/oh);
593                        w = Math.min(Math.max(mw, w), mxw);
594                        h = oh * (w/ow);
595                    break;
596                    case 'north':
597                        tw = w;
598                        w = ow * (h/oh);
599                        w = Math.min(Math.max(mw, w), mxw);
600                        h = oh * (w/ow);
601                        x += (tw - w) / 2;
602                        break;
603                    case 'southwest':
604                        h = oh * (w/ow);
605                        h = Math.min(Math.max(mh, h), mxh);
606                        tw = w;
607                        w = ow * (h/oh);
608                        x += tw - w;
609                        break;
610                    case 'west':
611                        th = h;
612                        h = oh * (w/ow);
613                        h = Math.min(Math.max(mh, h), mxh);
614                        y += (th - h) / 2;
615                        tw = w;
616                        w = ow * (h/oh);
617                        x += tw - w;
618                       break;
619                    case 'northwest':
620                        tw = w;
621                        th = h;
622                        h = oh * (w/ow);
623                        h = Math.min(Math.max(mh, h), mxh);
624                        w = ow * (h/oh);
625                        y += th - h;
626                        x += tw - w;
627                        break;
628                       
629                }
630            }
631            this.proxy.setBounds(x, y, w, h);
632            if(this.dynamic){
633                this.resizeElement();
634            }
635            }catch(ex){}
636        }
637    },
638
639    // private
640    handleOver : function(){
641        if(this.enabled){
642            this.el.addClass('x-resizable-over');
643        }
644    },
645
646    // private
647    handleOut : function(){
648        if(!this.resizing){
649            this.el.removeClass('x-resizable-over');
650        }
651    },
652   
653    /**
654     * Returns the element this component is bound to.
655     * @return {Ext.Element}
656     */
657    getEl : function(){
658        return this.el;
659    },
660   
661    /**
662     * Returns the resizeChild element (or null).
663     * @return {Ext.Element}
664     */
665    getResizeChild : function(){
666        return this.resizeChild;
667    },
668   
669    /**
670     * Destroys this resizable. If the element was wrapped and
671     * removeEl is not true then the element remains.
672     * @param {Boolean} removeEl (optional) true to remove the element from the DOM
673     */
674    destroy : function(removeEl){
675        Ext.destroy(this.dd, this.overlay, this.proxy);
676        this.overlay = null;
677        this.proxy = null;
678       
679        var ps = Ext.Resizable.positions;
680        for(var k in ps){
681            if(typeof ps[k] != 'function' && this[ps[k]]){
682                this[ps[k]].destroy();
683            }
684        }
685        if(removeEl){
686            this.el.update('');
687            Ext.destroy(this.el);
688            this.el = null;
689        }
690        this.purgeListeners();
691    },
692
693    syncHandleHeight : function(){
694        var h = this.el.getHeight(true);
695        if(this.west){
696            this.west.el.setHeight(h);
697        }
698        if(this.east){
699            this.east.el.setHeight(h);
700        }
701    }
702});
703
704// private
705// hash to map config positions to true positions
706Ext.Resizable.positions = {
707    n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast'
708};
709
710// private
711Ext.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
712    if(!this.tpl){
713        // only initialize the template if resizable is used
714        var tpl = Ext.DomHelper.createTemplate(
715            {tag: 'div', cls: 'x-resizable-handle x-resizable-handle-{0}'}
716        );
717        tpl.compile();
718        Ext.Resizable.Handle.prototype.tpl = tpl;
719    }
720    this.position = pos;
721    this.rz = rz;
722    this.el = this.tpl.append(rz.el.dom, [this.position], true);
723    this.el.unselectable();
724    if(transparent){
725        this.el.setOpacity(0);
726    }
727    this.el.on('mousedown', this.onMouseDown, this);
728    if(!disableTrackOver){
729        this.el.on({
730            scope: this,
731            mouseover: this.onMouseOver,
732            mouseout: this.onMouseOut
733        });
734    }
735};
736
737// private
738Ext.Resizable.Handle.prototype = {
739    // private
740    afterResize : function(rz){
741        // do nothing   
742    },
743    // private
744    onMouseDown : function(e){
745        this.rz.onMouseDown(this, e);
746    },
747    // private
748    onMouseOver : function(e){
749        this.rz.handleOver(this, e);
750    },
751    // private
752    onMouseOut : function(e){
753        this.rz.handleOut(this, e);
754    },
755    // private
756    destroy : function(){
757        Ext.destroy(this.el);
758        this.el = null;
759    }
760};
Note: See TracBrowser for help on using the repository browser.