source: trunk/web/addons/job_monarch/lib/extjs/source/widgets/Resizable.js @ 619

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

lib/:

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