~mortenoh/+junk/dhis2-detailed-import-export

« back to all changes in this revision

Viewing changes to gis/dhis-gis-geostat/mfbase/ext/source/widgets/Window.js

  • Committer: larshelge at gmail
  • Date: 2009-03-03 16:46:36 UTC
  • Revision ID: larshelge@gmail.com-20090303164636-2sjlrquo7ib1gf7r
Initial check-in

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Ext JS Library 2.2
 
3
 * Copyright(c) 2006-2008, Ext JS, LLC.
 
4
 * licensing@extjs.com
 
5
 * 
 
6
 * http://extjs.com/license
 
7
 */
 
8
 
 
9
/**
 
10
 * @class Ext.Window
 
11
 * @extends Ext.Panel
 
12
 * A specialized panel intended for use as an application window.  Windows are floated and draggable by default, and
 
13
 * also provide specific behavior like the ability to maximize and restore (with an event for minimizing, since the
 
14
 * minimize behavior is application-specific).  Windows can also be linked to a {@link Ext.WindowGroup} or managed
 
15
 * by the {@link Ext.WindowManager} to provide grouping, activation, to front/back and other application-specific behavior.
 
16
 * @constructor
 
17
 * @param {Object} config The config object
 
18
 */
 
19
Ext.Window = Ext.extend(Ext.Panel, {
 
20
    /**
 
21
     * @cfg {Number} x
 
22
     * The X position of the left edge of the Window on initial showing. Defaults to centering the Window within
 
23
     * the width of the Window's container {@link Ext.Element Element) (The Element that the Window is rendered to).
 
24
     */
 
25
    /**
 
26
     * @cfg {Number} y
 
27
     * The Y position of the top edge of the Window on initial showing. Defaults to centering the Window within
 
28
     * the height of the Window's container {@link Ext.Element Element) (The Element that the Window is rendered to).
 
29
     */
 
30
    /**
 
31
     * @cfg {Boolean} modal
 
32
     * True to make the window modal and mask everything behind it when displayed, false to display it without
 
33
     * restricting access to other UI elements (defaults to false).
 
34
     */
 
35
    /**
 
36
     * @cfg {String/Element} animateTarget
 
37
     * Id or element from which the window should animate while opening (defaults to null with no animation).
 
38
     */
 
39
    /**
 
40
     * @cfg {String} resizeHandles
 
41
     * A valid {@link Ext.Resizable} handles config string (defaults to 'all').  Only applies when resizable = true.
 
42
     */
 
43
    /**
 
44
     * @cfg {Ext.WindowGroup} manager
 
45
     * A reference to the WindowGroup that should manage this window (defaults to {@link Ext.WindowMgr}).
 
46
     */
 
47
    /**
 
48
    * @cfg {String/Number/Button} defaultButton
 
49
    * The id / index of a button or a button instance to focus when this window received the focus.
 
50
    */
 
51
    /**
 
52
    * @cfg {Function} onEsc
 
53
    * Allows override of the built-in processing for the escape key. Default action
 
54
    * is to close the Window (performing whatever action is specified in {@link #closeAction}.
 
55
    * To prevent the Window closing when the escape key is pressed, specify this as
 
56
    * Ext.emptyFn (See {@link Ext#emptyFn}).
 
57
    */
 
58
    /**
 
59
    * @cfg {String} baseCls
 
60
    * The base CSS class to apply to this panel's element (defaults to 'x-window').
 
61
    */
 
62
    baseCls : 'x-window',
 
63
    /**
 
64
     * @cfg {Boolean} resizable
 
65
     * True to allow user resizing at each edge and corner of the window, false to disable resizing (defaults to true).
 
66
     */
 
67
    resizable:true,
 
68
    /**
 
69
     * @cfg {Boolean} draggable
 
70
     * True to allow the window to be dragged by the header bar, false to disable dragging (defaults to true).  Note
 
71
     * that by default the window will be centered in the viewport, so if dragging is disabled the window may need
 
72
     * to be positioned programmatically after render (e.g., myWindow.setPosition(100, 100);).
 
73
     */
 
74
    draggable:true,
 
75
    /**
 
76
     * @cfg {Boolean} closable
 
77
     * <p>True to display the 'close' tool button and allow the user to close the window, false to
 
78
     * hide the button and disallow closing the window (default to true).</p>
 
79
     * <p>By default, when close is requested by either clicking the close button in the header
 
80
     * or pressing ESC when the Window has focus, the {@link #close} method will be called. This
 
81
     * will <i>destroy</i> the Window and its content meaning that it may not be reused.</p>
 
82
     * <p>To make closing a Window <i>hide</i> the Window so that it may be reused, set
 
83
     * {@link #closeAction} to 'hide'.
 
84
     */
 
85
    closable : true,
 
86
    /**
 
87
     * @cfg {Boolean} constrain
 
88
     * True to constrain the window to the viewport, false to allow it to fall outside of the viewport
 
89
     * (defaults to false).  Optionally the header only can be constrained using {@link #constrainHeader}.
 
90
     */
 
91
    constrain:false,
 
92
    /**
 
93
     * @cfg {Boolean} constrainHeader
 
94
     * True to constrain the window header to the viewport, allowing the window body to fall outside of the viewport,
 
95
     * false to allow the header to fall outside the viewport (defaults to false).  Optionally the entire window
 
96
     * can be constrained using {@link #constrain}.
 
97
     */
 
98
    constrainHeader:false,
 
99
    /**
 
100
     * @cfg {Boolean} plain
 
101
     * True to render the window body with a transparent background so that it will blend into the framing
 
102
     * elements, false to add a lighter background color to visually highlight the body element and separate it
 
103
     * more distinctly from the surrounding frame (defaults to false).
 
104
     */
 
105
    plain:false,
 
106
    /**
 
107
     * @cfg {Boolean} minimizable
 
108
     * True to display the 'minimize' tool button and allow the user to minimize the window, false to hide the button
 
109
     * and disallow minimizing the window (defaults to false).  Note that this button provides no implementation --
 
110
     * the behavior of minimizing a window is implementation-specific, so the minimize event must be handled and a
 
111
     * custom minimize behavior implemented for this option to be useful.
 
112
     */
 
113
    minimizable : false,
 
114
    /**
 
115
     * @cfg {Boolean} maximizable
 
116
     * True to display the 'maximize' tool button and allow the user to maximize the window, false to hide the button
 
117
     * and disallow maximizing the window (defaults to false).  Note that when a window is maximized, the tool button
 
118
     * will automatically change to a 'restore' button with the appropriate behavior already built-in that will
 
119
     * restore the window to its previous size.
 
120
     */
 
121
    maximizable : false,
 
122
    /**
 
123
     * @cfg {Number} minHeight
 
124
     * The minimum height in pixels allowed for this window (defaults to 100).  Only applies when resizable = true.
 
125
     */
 
126
    minHeight: 100,
 
127
    /**
 
128
     * @cfg {Number} minWidth
 
129
     * The minimum width in pixels allowed for this window (defaults to 200).  Only applies when resizable = true.
 
130
     */
 
131
    minWidth: 200,
 
132
    /**
 
133
     * @cfg {Boolean} expandOnShow
 
134
     * True to always expand the window when it is displayed, false to keep it in its current state (which may be
 
135
     * collapsed) when displayed (defaults to true).
 
136
     */
 
137
    expandOnShow: true,
 
138
    /**
 
139
     * @cfg {String} closeAction
 
140
     * The action to take when the close button is clicked.  The default action is 'close' which will actually remove
 
141
     * the window from the DOM and destroy it.  The other valid option is 'hide' which will simply hide the window
 
142
     * by setting visibility to hidden and applying negative offsets, keeping the window available to be redisplayed
 
143
     * via the {@link #show} method.
 
144
     */
 
145
    closeAction: 'close',
 
146
    /**
 
147
     * @cfg {String} elements
 
148
     * A comma-delimited list of panel elements to initialize when the window is rendered.  Normally, this list will be
 
149
     * generated automatically based on the items added to the window at config time, but sometimes it might be useful to
 
150
     * make sure a structural element is rendered even if not specified at config time (for example, you may want
 
151
     * to add a button or toolbar dynamically after the window has been rendered).  Adding those elements to this
 
152
     * list will allocate the required placeholders in the window when it is rendered.  Valid values are<ul>
 
153
     * <li><b>header</b> (required)</li>
 
154
     * <li><b>tbar</b> (top bar)</li>
 
155
     * <li><b>body</b> (required)</li>
 
156
     * <li><b>bbar</b> (bottom bar)</li>
 
157
     * <li><b>footer</b><li>
 
158
     * </ul>
 
159
     * Defaults to 'header,body'.
 
160
     */
 
161
    elements: 'header,body',
 
162
 
 
163
    // inherited docs, same default
 
164
    collapsible:false,
 
165
 
 
166
    // private
 
167
    initHidden : true,
 
168
    /**
 
169
    * @cfg {Boolean} monitorResize @hide
 
170
    * This is automatically managed based on the value of constrain and constrainToHeader
 
171
    */
 
172
    monitorResize : true,
 
173
    /** @cfg {Boolean} frame @hide */
 
174
    frame:true,
 
175
    /** @cfg {Boolean} floating @hide */
 
176
    floating:true,
 
177
 
 
178
    // private
 
179
    initComponent : function(){
 
180
        Ext.Window.superclass.initComponent.call(this);
 
181
        this.addEvents(
 
182
            /**
 
183
             * @event activate
 
184
             * Fires after the window has been visually activated via {@link setActive}.
 
185
             * @param {Ext.Window} this
 
186
             */
 
187
            /**
 
188
             * @event deactivate
 
189
             * Fires after the window has been visually deactivated via {@link setActive}.
 
190
             * @param {Ext.Window} this
 
191
             */
 
192
            /**
 
193
             * @event resize
 
194
             * Fires after the window has been resized.
 
195
             * @param {Ext.Window} this
 
196
             * @param {Number} width The window's new width
 
197
             * @param {Number} height The window's new height
 
198
             */
 
199
            'resize',
 
200
            /**
 
201
             * @event maximize
 
202
             * Fires after the window has been maximized.
 
203
             * @param {Ext.Window} this
 
204
             */
 
205
            'maximize',
 
206
            /**
 
207
             * @event minimize
 
208
             * Fires after the window has been minimized.
 
209
             * @param {Ext.Window} this
 
210
             */
 
211
            'minimize',
 
212
            /**
 
213
             * @event restore
 
214
             * Fires after the window has been restored to its original size after being maximized.
 
215
             * @param {Ext.Window} this
 
216
             */
 
217
            'restore'
 
218
        );
 
219
    },
 
220
 
 
221
    // private
 
222
    getState : function(){
 
223
        return Ext.apply(Ext.Window.superclass.getState.call(this) || {}, this.getBox());
 
224
    },
 
225
 
 
226
    // private
 
227
    onRender : function(ct, position){
 
228
        Ext.Window.superclass.onRender.call(this, ct, position);
 
229
 
 
230
        if(this.plain){
 
231
            this.el.addClass('x-window-plain');
 
232
        }
 
233
 
 
234
        // this element allows the Window to be focused for keyboard events
 
235
        this.focusEl = this.el.createChild({
 
236
                    tag: "a", href:"#", cls:"x-dlg-focus",
 
237
                    tabIndex:"-1", html: "&#160;"});
 
238
        this.focusEl.swallowEvent('click', true);
 
239
 
 
240
        this.proxy = this.el.createProxy("x-window-proxy");
 
241
        this.proxy.enableDisplayMode('block');
 
242
 
 
243
        if(this.modal){
 
244
            this.mask = this.container.createChild({cls:"ext-el-mask"}, this.el.dom);
 
245
            this.mask.enableDisplayMode("block");
 
246
            this.mask.hide();
 
247
        }
 
248
    },
 
249
 
 
250
    // private
 
251
    initEvents : function(){
 
252
        Ext.Window.superclass.initEvents.call(this);
 
253
        if(this.animateTarget){
 
254
            this.setAnimateTarget(this.animateTarget);
 
255
        }
 
256
 
 
257
        if(this.resizable){
 
258
            this.resizer = new Ext.Resizable(this.el, {
 
259
                minWidth: this.minWidth,
 
260
                minHeight:this.minHeight,
 
261
                handles: this.resizeHandles || "all",
 
262
                pinned: true,
 
263
                resizeElement : this.resizerAction
 
264
            });
 
265
            this.resizer.window = this;
 
266
            this.resizer.on("beforeresize", this.beforeResize, this);
 
267
        }
 
268
 
 
269
        if(this.draggable){
 
270
            this.header.addClass("x-window-draggable");
 
271
        }
 
272
        this.initTools();
 
273
 
 
274
        this.el.on("mousedown", this.toFront, this);
 
275
        this.manager = this.manager || Ext.WindowMgr;
 
276
        this.manager.register(this);
 
277
        this.hidden = true;
 
278
        if(this.maximized){
 
279
            this.maximized = false;
 
280
            this.maximize();
 
281
        }
 
282
        if(this.closable){
 
283
            var km = this.getKeyMap();
 
284
            km.on(27, this.onEsc, this);
 
285
            km.disable();
 
286
        }
 
287
    },
 
288
 
 
289
    initDraggable : function(){
 
290
        /**
 
291
         * If this Window is configured {@link #draggable}, this property will contain
 
292
         * an instance of {@link Ext.dd.DD} which handles dragging the Window's DOM Element.
 
293
         * @type Ext.dd.DD
 
294
         * @property dd
 
295
         */
 
296
        this.dd = new Ext.Window.DD(this);
 
297
    },
 
298
 
 
299
   // private
 
300
    onEsc : function(){
 
301
        this[this.closeAction]();
 
302
    },
 
303
 
 
304
    // private
 
305
    beforeDestroy : function(){
 
306
        Ext.destroy(
 
307
            this.resizer,
 
308
            this.dd,
 
309
            this.proxy,
 
310
            this.mask
 
311
        );
 
312
        Ext.Window.superclass.beforeDestroy.call(this);
 
313
    },
 
314
 
 
315
    // private
 
316
    onDestroy : function(){
 
317
        if(this.manager){
 
318
            this.manager.unregister(this);
 
319
        }
 
320
        Ext.Window.superclass.onDestroy.call(this);
 
321
    },
 
322
 
 
323
    // private
 
324
    initTools : function(){
 
325
        if(this.minimizable){
 
326
            this.addTool({
 
327
                id: 'minimize',
 
328
                handler: this.minimize.createDelegate(this, [])
 
329
            });
 
330
        }
 
331
        if(this.maximizable){
 
332
            this.addTool({
 
333
                id: 'maximize',
 
334
                handler: this.maximize.createDelegate(this, [])
 
335
            });
 
336
            this.addTool({
 
337
                id: 'restore',
 
338
                handler: this.restore.createDelegate(this, []),
 
339
                hidden:true
 
340
            });
 
341
            this.header.on('dblclick', this.toggleMaximize, this);
 
342
        }
 
343
        if(this.closable){
 
344
            this.addTool({
 
345
                id: 'close',
 
346
                handler: this[this.closeAction].createDelegate(this, [])
 
347
            });
 
348
        }
 
349
    },
 
350
 
 
351
    // private
 
352
    resizerAction : function(){
 
353
        var box = this.proxy.getBox();
 
354
        this.proxy.hide();
 
355
        this.window.handleResize(box);
 
356
        return box;
 
357
    },
 
358
 
 
359
    // private
 
360
    beforeResize : function(){
 
361
        this.resizer.minHeight = Math.max(this.minHeight, this.getFrameHeight() + 40); // 40 is a magic minimum content size?
 
362
        this.resizer.minWidth = Math.max(this.minWidth, this.getFrameWidth() + 40);
 
363
        this.resizeBox = this.el.getBox();
 
364
    },
 
365
 
 
366
    // private
 
367
    updateHandles : function(){
 
368
        if(Ext.isIE && this.resizer){
 
369
            this.resizer.syncHandleHeight();
 
370
            this.el.repaint();
 
371
        }
 
372
    },
 
373
 
 
374
    // private
 
375
    handleResize : function(box){
 
376
        var rz = this.resizeBox;
 
377
        if(rz.x != box.x || rz.y != box.y){
 
378
            this.updateBox(box);
 
379
        }else{
 
380
            this.setSize(box);
 
381
        }
 
382
        this.focus();
 
383
        this.updateHandles();
 
384
        this.saveState();
 
385
        if(this.layout){
 
386
            this.doLayout();
 
387
        }
 
388
        this.fireEvent("resize", this, box.width, box.height);
 
389
    },
 
390
 
 
391
    /**
 
392
     * Focuses the window.  If a defaultButton is set, it will receive focus, otherwise the
 
393
     * window itself will receive focus.
 
394
     */
 
395
    focus : function(){
 
396
        var f = this.focusEl, db = this.defaultButton, t = typeof db;
 
397
        if(t != 'undefined'){
 
398
            if(t == 'number'){
 
399
                f = this.buttons[db];
 
400
            }else if(t == 'string'){
 
401
                f = Ext.getCmp(db);
 
402
            }else{
 
403
                f = db;
 
404
            }
 
405
        }
 
406
        f.focus.defer(10, f);
 
407
    },
 
408
 
 
409
    /**
 
410
     * Sets the target element from which the window should animate while opening.
 
411
     * @param {String/Element} el The target element or id
 
412
     */
 
413
    setAnimateTarget : function(el){
 
414
        el = Ext.get(el);
 
415
        this.animateTarget = el;
 
416
    },
 
417
 
 
418
    // private
 
419
    beforeShow : function(){
 
420
        delete this.el.lastXY;
 
421
        delete this.el.lastLT;
 
422
        if(this.x === undefined || this.y === undefined){
 
423
            var xy = this.el.getAlignToXY(this.container, 'c-c');
 
424
            var pos = this.el.translatePoints(xy[0], xy[1]);
 
425
            this.x = this.x === undefined? pos.left : this.x;
 
426
            this.y = this.y === undefined? pos.top : this.y;
 
427
        }
 
428
        this.el.setLeftTop(this.x, this.y);
 
429
 
 
430
        if(this.expandOnShow){
 
431
            this.expand(false);
 
432
        }
 
433
 
 
434
        if(this.modal){
 
435
            Ext.getBody().addClass("x-body-masked");
 
436
            this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
 
437
            this.mask.show();
 
438
        }
 
439
    },
 
440
 
 
441
    /**
 
442
     * Shows the window, rendering it first if necessary, or activates it and brings it to front if hidden.
 
443
     * @param {String/Element} animateTarget (optional) The target element or id from which the window should
 
444
     * animate while opening (defaults to undefined with no animation)
 
445
     * @param {Function} callback (optional) A callback function to call after the window is displayed
 
446
     * @param {Object} scope (optional) The scope in which to execute the callback
 
447
     */
 
448
    show : function(animateTarget, cb, scope){
 
449
        if(!this.rendered){
 
450
            this.render(Ext.getBody());
 
451
        }
 
452
        if(this.hidden === false){
 
453
            this.toFront();
 
454
            return;
 
455
        }
 
456
        if(this.fireEvent("beforeshow", this) === false){
 
457
            return;
 
458
        }
 
459
        if(cb){
 
460
            this.on('show', cb, scope, {single:true});
 
461
        }
 
462
        this.hidden = false;
 
463
        if(animateTarget !== undefined){
 
464
            this.setAnimateTarget(animateTarget);
 
465
        }
 
466
        this.beforeShow();
 
467
        if(this.animateTarget){
 
468
            this.animShow();
 
469
        }else{
 
470
            this.afterShow();
 
471
        }
 
472
    },
 
473
 
 
474
    // private
 
475
    afterShow : function(){
 
476
        this.proxy.hide();
 
477
        this.el.setStyle('display', 'block');
 
478
        this.el.show();
 
479
        if(this.maximized){
 
480
            this.fitContainer();
 
481
        }
 
482
        if(Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug
 
483
                this.cascade(this.setAutoScroll);
 
484
        }
 
485
 
 
486
        if(this.monitorResize || this.modal || this.constrain || this.constrainHeader){
 
487
            Ext.EventManager.onWindowResize(this.onWindowResize, this);
 
488
        }
 
489
        this.doConstrain();
 
490
        if(this.layout){
 
491
            this.doLayout();
 
492
        }
 
493
        if(this.keyMap){
 
494
            this.keyMap.enable();
 
495
        }
 
496
        this.toFront();
 
497
        this.updateHandles();
 
498
        this.fireEvent("show", this);
 
499
    },
 
500
 
 
501
    // private
 
502
    animShow : function(){
 
503
        this.proxy.show();
 
504
        this.proxy.setBox(this.animateTarget.getBox());
 
505
        this.proxy.setOpacity(0);
 
506
        var b = this.getBox(false);
 
507
        b.callback = this.afterShow;
 
508
        b.scope = this;
 
509
        b.duration = .25;
 
510
        b.easing = 'easeNone';
 
511
        b.opacity = .5;
 
512
        b.block = true;
 
513
        this.el.setStyle('display', 'none');
 
514
        this.proxy.shift(b);
 
515
    },
 
516
 
 
517
    /**
 
518
     * Hides the window, setting it to invisible and applying negative offsets.
 
519
     * @param {String/Element} animateTarget (optional) The target element or id to which the window should
 
520
     * animate while hiding (defaults to null with no animation)
 
521
     * @param {Function} callback (optional) A callback function to call after the window is hidden
 
522
     * @param {Object} scope (optional) The scope in which to execute the callback
 
523
     */
 
524
    hide : function(animateTarget, cb, scope){
 
525
        if(this.activeGhost){ // drag active?
 
526
            this.hide.defer(100, this, [animateTarget, cb, scope]);
 
527
            return;
 
528
        }
 
529
        if(this.hidden || this.fireEvent("beforehide", this) === false){
 
530
            return;
 
531
        }
 
532
        if(cb){
 
533
            this.on('hide', cb, scope, {single:true});
 
534
        }
 
535
        this.hidden = true;
 
536
        if(animateTarget !== undefined){
 
537
            this.setAnimateTarget(animateTarget);
 
538
        }
 
539
        if(this.animateTarget){
 
540
            this.animHide();
 
541
        }else{
 
542
            this.el.hide();
 
543
            this.afterHide();
 
544
        }
 
545
    },
 
546
 
 
547
    // private
 
548
    afterHide : function(){
 
549
        this.proxy.hide();
 
550
        if(this.monitorResize || this.modal || this.constrain || this.constrainHeader){
 
551
            Ext.EventManager.removeResizeListener(this.onWindowResize, this);
 
552
        }
 
553
        if(this.modal){
 
554
            this.mask.hide();
 
555
            Ext.getBody().removeClass("x-body-masked");
 
556
        }
 
557
        if(this.keyMap){
 
558
            this.keyMap.disable();
 
559
        }
 
560
        this.fireEvent("hide", this);
 
561
    },
 
562
 
 
563
    // private
 
564
    animHide : function(){
 
565
        this.proxy.setOpacity(.5);
 
566
        this.proxy.show();
 
567
        var tb = this.getBox(false);
 
568
        this.proxy.setBox(tb);
 
569
        this.el.hide();
 
570
        var b = this.animateTarget.getBox();
 
571
        b.callback = this.afterHide;
 
572
        b.scope = this;
 
573
        b.duration = .25;
 
574
        b.easing = 'easeNone';
 
575
        b.block = true;
 
576
        b.opacity = 0;
 
577
        this.proxy.shift(b);
 
578
    },
 
579
 
 
580
    // private
 
581
    onWindowResize : function(){
 
582
        if(this.maximized){
 
583
            this.fitContainer();
 
584
        }
 
585
        if(this.modal){
 
586
            this.mask.setSize('100%', '100%');
 
587
            var force = this.mask.dom.offsetHeight;
 
588
            this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
 
589
        }
 
590
        this.doConstrain();
 
591
    },
 
592
 
 
593
    // private
 
594
    doConstrain : function(){
 
595
        if(this.constrain || this.constrainHeader){
 
596
            var offsets;
 
597
            if(this.constrain){
 
598
                offsets = {
 
599
                    right:this.el.shadowOffset,
 
600
                    left:this.el.shadowOffset,
 
601
                    bottom:this.el.shadowOffset
 
602
                };
 
603
            }else {
 
604
                var s = this.getSize();
 
605
                offsets = {
 
606
                    right:-(s.width - 100),
 
607
                    bottom:-(s.height - 25)
 
608
                };
 
609
            }
 
610
 
 
611
            var xy = this.el.getConstrainToXY(this.container, true, offsets);
 
612
            if(xy){
 
613
                this.setPosition(xy[0], xy[1]);
 
614
            }
 
615
        }
 
616
    },
 
617
 
 
618
    // private - used for dragging
 
619
    ghost : function(cls){
 
620
        var ghost = this.createGhost(cls);
 
621
        var box = this.getBox(true);
 
622
        ghost.setLeftTop(box.x, box.y);
 
623
        ghost.setWidth(box.width);
 
624
        this.el.hide();
 
625
        this.activeGhost = ghost;
 
626
        return ghost;
 
627
    },
 
628
 
 
629
    // private
 
630
    unghost : function(show, matchPosition){
 
631
        if(show !== false){
 
632
            this.el.show();
 
633
            this.focus();
 
634
                if(Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug
 
635
                        this.cascade(this.setAutoScroll);
 
636
                }
 
637
        }
 
638
        if(matchPosition !== false){
 
639
            this.setPosition(this.activeGhost.getLeft(true), this.activeGhost.getTop(true));
 
640
        }
 
641
        this.activeGhost.hide();
 
642
        this.activeGhost.remove();
 
643
        delete this.activeGhost;
 
644
    },
 
645
 
 
646
    /**
 
647
     * Placeholder method for minimizing the window.  By default, this method simply fires the {@link #minimize} event
 
648
     * since the behavior of minimizing a window is application-specific.  To implement custom minimize behavior,
 
649
     * either the minimize event can be handled or this method can be overridden.
 
650
     */
 
651
    minimize : function(){
 
652
        this.fireEvent('minimize', this);
 
653
    },
 
654
 
 
655
    /**
 
656
     * Closes the window, removes it from the DOM and destroys the window object.  The beforeclose event is fired
 
657
     * before the close happens and will cancel the close action if it returns false.
 
658
     */
 
659
    close : function(){
 
660
        if(this.fireEvent("beforeclose", this) !== false){
 
661
            this.hide(null, function(){
 
662
                this.fireEvent('close', this);
 
663
                this.destroy();
 
664
            }, this);
 
665
        }
 
666
    },
 
667
 
 
668
    /**
 
669
     * Fits the window within its current container and automatically replaces the 'maximize' tool button with
 
670
     * the 'restore' tool button.
 
671
     */
 
672
    maximize : function(){
 
673
        if(!this.maximized){
 
674
            this.expand(false);
 
675
            this.restoreSize = this.getSize();
 
676
            this.restorePos = this.getPosition(true);
 
677
            if (this.maximizable){
 
678
                this.tools.maximize.hide();
 
679
                this.tools.restore.show();
 
680
            }
 
681
            this.maximized = true;
 
682
            this.el.disableShadow();
 
683
 
 
684
            if(this.dd){
 
685
                this.dd.lock();
 
686
            }
 
687
            if(this.collapsible){
 
688
                this.tools.toggle.hide();
 
689
            }
 
690
            this.el.addClass('x-window-maximized');
 
691
            this.container.addClass('x-window-maximized-ct');
 
692
 
 
693
            this.setPosition(0, 0);
 
694
            this.fitContainer();
 
695
            this.fireEvent('maximize', this);
 
696
        }
 
697
    },
 
698
 
 
699
    /**
 
700
     * Restores a maximized window back to its original size and position prior to being maximized and also replaces
 
701
     * the 'restore' tool button with the 'maximize' tool button.
 
702
     */
 
703
    restore : function(){
 
704
        if(this.maximized){
 
705
            this.el.removeClass('x-window-maximized');
 
706
            this.tools.restore.hide();
 
707
            this.tools.maximize.show();
 
708
            this.setPosition(this.restorePos[0], this.restorePos[1]);
 
709
            this.setSize(this.restoreSize.width, this.restoreSize.height);
 
710
            delete this.restorePos;
 
711
            delete this.restoreSize;
 
712
            this.maximized = false;
 
713
            this.el.enableShadow(true);
 
714
 
 
715
            if(this.dd){
 
716
                this.dd.unlock();
 
717
            }
 
718
            if(this.collapsible){
 
719
                this.tools.toggle.show();
 
720
            }
 
721
            this.container.removeClass('x-window-maximized-ct');
 
722
 
 
723
            this.doConstrain();
 
724
            this.fireEvent('restore', this);
 
725
        }
 
726
    },
 
727
 
 
728
    /**
 
729
     * A shortcut method for toggling between {@link #maximize} and {@link #restore} based on the current maximized
 
730
     * state of the window.
 
731
     */
 
732
    toggleMaximize : function(){
 
733
        this[this.maximized ? 'restore' : 'maximize']();
 
734
    },
 
735
 
 
736
    // private
 
737
    fitContainer : function(){
 
738
        var vs = this.container.getViewSize();
 
739
        this.setSize(vs.width, vs.height);
 
740
    },
 
741
 
 
742
    // private
 
743
    // z-index is managed by the WindowManager and may be overwritten at any time
 
744
    setZIndex : function(index){
 
745
        if(this.modal){
 
746
            this.mask.setStyle("z-index", index);
 
747
        }
 
748
        this.el.setZIndex(++index);
 
749
        index += 5;
 
750
 
 
751
        if(this.resizer){
 
752
            this.resizer.proxy.setStyle("z-index", ++index);
 
753
        }
 
754
 
 
755
        this.lastZIndex = index;
 
756
    },
 
757
 
 
758
    /**
 
759
     * Aligns the window to the specified element
 
760
     * @param {Mixed} element The element to align to.
 
761
     * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details).
 
762
     * @param {Array} offsets (optional) Offset the positioning by [x, y]
 
763
     * @return {Ext.Window} this
 
764
     */
 
765
    alignTo : function(element, position, offsets){
 
766
        var xy = this.el.getAlignToXY(element, position, offsets);
 
767
        this.setPagePosition(xy[0], xy[1]);
 
768
        return this;
 
769
    },
 
770
 
 
771
    /**
 
772
     * Anchors this window to another element and realigns it when the window is resized or scrolled.
 
773
     * @param {Mixed} element The element to align to.
 
774
     * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details)
 
775
     * @param {Array} offsets (optional) Offset the positioning by [x, y]
 
776
     * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
 
777
     * is a number, it is used as the buffer delay (defaults to 50ms).
 
778
     * @return {Ext.Window} this
 
779
     */
 
780
    anchorTo : function(el, alignment, offsets, monitorScroll, _pname){
 
781
        var action = function(){
 
782
            this.alignTo(el, alignment, offsets);
 
783
        };
 
784
        Ext.EventManager.onWindowResize(action, this);
 
785
        var tm = typeof monitorScroll;
 
786
        if(tm != 'undefined'){
 
787
            Ext.EventManager.on(window, 'scroll', action, this,
 
788
                {buffer: tm == 'number' ? monitorScroll : 50});
 
789
        }
 
790
        action.call(this);
 
791
        this[_pname] = action;
 
792
        return this;
 
793
    },
 
794
 
 
795
    /**
 
796
     * Brings this window to the front of any other visible windows
 
797
     * @return {Ext.Window} this
 
798
     */
 
799
    toFront : function(){
 
800
        if(this.manager.bringToFront(this)){
 
801
            this.focus();
 
802
        }
 
803
        return this;
 
804
    },
 
805
 
 
806
    /**
 
807
     * Makes this the active window by showing its shadow, or deactivates it by hiding its shadow.  This method also
 
808
     * fires the {@link #activate} or {@link #deactivate} event depending on which action occurred.
 
809
     * @param {Boolean} active True to activate the window, false to deactivate it (defaults to false)
 
810
     */
 
811
    setActive : function(active){
 
812
        if(active){
 
813
            if(!this.maximized){
 
814
                this.el.enableShadow(true);
 
815
            }
 
816
            this.fireEvent('activate', this);
 
817
        }else{
 
818
            this.el.disableShadow();
 
819
            this.fireEvent('deactivate', this);
 
820
        }
 
821
    },
 
822
 
 
823
    /**
 
824
     * Sends this window to the back of (lower z-index than) any other visible windows
 
825
     * @return {Ext.Window} this
 
826
     */
 
827
    toBack : function(){
 
828
        this.manager.sendToBack(this);
 
829
        return this;
 
830
    },
 
831
 
 
832
    /**
 
833
     * Centers this window in the viewport
 
834
     * @return {Ext.Window} this
 
835
     */
 
836
    center : function(){
 
837
        var xy = this.el.getAlignToXY(this.container, 'c-c');
 
838
        this.setPagePosition(xy[0], xy[1]);
 
839
        return this;
 
840
    }
 
841
 
 
842
    /**
 
843
     * @cfg {Boolean} autoWidth @hide
 
844
     **/
 
845
});
 
846
Ext.reg('window', Ext.Window);
 
847
 
 
848
// private - custom Window DD implementation
 
849
Ext.Window.DD = function(win){
 
850
    this.win = win;
 
851
    Ext.Window.DD.superclass.constructor.call(this, win.el.id, 'WindowDD-'+win.id);
 
852
    this.setHandleElId(win.header.id);
 
853
    this.scroll = false;
 
854
};
 
855
 
 
856
Ext.extend(Ext.Window.DD, Ext.dd.DD, {
 
857
    moveOnly:true,
 
858
    headerOffsets:[100, 25],
 
859
    startDrag : function(){
 
860
        var w = this.win;
 
861
        this.proxy = w.ghost();
 
862
        if(w.constrain !== false){
 
863
            var so = w.el.shadowOffset;
 
864
            this.constrainTo(w.container, {right: so, left: so, bottom: so});
 
865
        }else if(w.constrainHeader !== false){
 
866
            var s = this.proxy.getSize();
 
867
            this.constrainTo(w.container, {right: -(s.width-this.headerOffsets[0]), bottom: -(s.height-this.headerOffsets[1])});
 
868
        }
 
869
    },
 
870
    b4Drag : Ext.emptyFn,
 
871
 
 
872
    onDrag : function(e){
 
873
        this.alignElWithMouse(this.proxy, e.getPageX(), e.getPageY());
 
874
    },
 
875
 
 
876
    endDrag : function(e){
 
877
        this.win.unghost();
 
878
        this.win.saveState();
 
879
    }
 
880
});