Ext.ux.Accordion extension class code:
1 // vim: ts=2:sw=2:nu:fdc=4:nospell
2
3 // Create user extensions namespace (Ext.ux)
4 Ext.namespace('Ext.ux');
5
6 /**
7 * Ext.ux.Accordion Extension Class
8 *
9 * @author Ing. Jozef Sakalos
10 * @version $Id: Ext.ux.Accordion.js 152 2007-08-21 17:46:03Z jozo $
11 *
12 * @class Ext.ux.Accordion
13 * @extends Ext.ContentPanel
14 * @constructor
15 * @param {String/HTMLElement/Element} el The container element for this panel
16 * @param {String/Object} config A string to set only the title or a config object
17 * @cfg {Boolean} animate global animation flag for all panels. (defaults to true)
18 * @cfg {Boolean} boxWrap set to true to wrap wrapEl the body is child of (defaults to false)
19 * @cfg {Boolean} draggable set to false to disallow panels dragging (defaults to true)
20 * @cfg {Boolean} fitHeight set to true if you use fixed height dock
21 * @cfg {Boolean} forceOrder set to true if to disable reordering of panels (defaults to false)
22 * @cfg {Boolean} independent true to make panels independent (defaults to false)
23 * @cfg {Integer} initialHeight Initial height to set box to (defaults to 0)
24 * @cfg {Boolean} keepState Set to false to exclude this accordion from state management (defaults to true)
25 * @cfg {Boolean} monitorWindowResize if true panels are moved to
26 * viewport if window is small (defaults to true)
27 * @cfg {Boolean} resizable global resizable flag for all panels (defaults to true)
28 * @cfg {Boolean} undockable true to allow undocking of panels (defaults to true)
29 * @cfg {Boolean} useShadow global useShadow flag for all panels. (defaults to true)
30 * @cfg {Element/HTMLElement/String} wrapEl Element to wrap with nice surrounding
31 */
32 Ext.ux.Accordion = function(el, config) {
33
34 // call parent constructor
35 Ext.ux.Accordion.superclass.constructor.call(this, el, config);
36
37 // create collection for panels
38 this.items = new Ext.util.MixedCollection();
39
40 // assume no panel is expanded
41 this.expanded = null;
42
43 // {{{
44 // install event handlers
45 this.on({
46
47 // {{{
48 // runs before expansion. Triggered by panel's beforeexpand event
49 beforeexpand: {
50 scope: this
51 , fn: function(panel) {
52 // raise panel above others
53 if(!panel.docked) {
54 this.raise(panel);
55 }
56
57 // set fixed height
58 panel.autoSize();
59 // var panelBodyHeight;
60 // if(this.fitHeight && panel.docked) {
61 // panelBodyHeight = this.getPanelBodyHeight();
62 // if(panelBodyHeight) {
63 // panel.body.setHeight(panelBodyHeight);
64 // }
65 // }
66
67 if(panel.docked) {
68 this.expandCount++;
69 this.expanding = true;
70 // this.setDockScroll(false);
71 }
72
73 // don't collapse others if independent or not docked
74 if(this.independent || !panel.docked) {
75 return this;
76 }
77
78 // collapse expanded panel
79 if(this.expanded && this.expanded.docked) {
80 this.expanded.collapse();
81 }
82
83 // remember this panel as expanded
84 this.expanded = panel;
85 }}
86 // }}}
87 // {{{
88 // runs before panel collapses. Triggered by panel's beforecollapse event
89 , beforecollapse: {
90 scope: this
91 , fn: function(panel) {
92
93 // raise panel if not docked
94 if(!panel.docked) {
95 this.raise(panel);
96 }
97 return this;
98 }}
99 // }}}
100 // {{{
101 // runs on when panel expands (before animation). Triggered by panel's expand event
102 , expand: {
103 scope: this
104 , fn: function(panel) {
105 if(this.hideOtherOnExpand) {
106 this.hideOther(panel);
107 }
108 this.fireEvent('panelexpand', panel);
109 }}
110 // }}}
111 // {{{
112 // runs on when panel collapses (before animation). Triggered by panel's collapse event
113 , collapse: {
114 scope: this
115 , fn: function(panel) {
116 this.fireEvent('panelcollapse', panel);
117 }}
118 // }}}
119 // {{{
120 // runs on when animation is completed. Triggered by panel's animationcompleted event
121 , animationcompleted: {
122 scope: this
123 , fn: function(panel) {
124 var box = panel.el.getBox();
125 this.expandCount = (this.expandCount && this.expanding) ? --this.expandCount : 0;
126 if((0 === this.expandCount) && this.expanding) {
127 // this.setDockScroll(true);
128 this.expanding = false;
129 }
130 if(this.hideOtherOnExpand) {
131 if(panel.collapsed && panel.docked) {
132 this.showOther(panel);
133 }
134 // else if(panel.docked) {
135 // this.hideOther(panel);
136 // }
137 }
138 // this.fireEvent('panelbox', panel, box);
139 }}
140 // }}}
141 // {{{
142 // runs when panel is pinned. Triggered by panel's pinned event
143 , pinned: {
144 scope: this
145 , fn: function(panel, pinned) {
146 if(!pinned) {
147 if(panel.collapseOnUnpin) {
148 panel.collapse();
149 }
150 else if(!this.independent) {
151 this.items.each(function(p) {
152 if(p !== panel && p.docked && !p.pinned) {
153 p.collapse();
154 }
155 });
156 this.expanded = panel;
157 }
158 }
159 if(this.hideOtherOnExpand) {
160 if(panel.docked && pinned) {
161 this.showOther(panel);
162 }
163 }
164 this.fireEvent('panelpinned', panel, pinned);
165 }}
166 // }}}
167
168 , destroy: {
169 scope:this
170 , fn: function(panel) {
171 this.items.removeKey(panel.id);
172 this.updateOrder();
173 }}
174 });
175 // }}}
176 // {{{
177 // add events
178 this.addEvents({
179 /**
180 * Fires when a panel of the dock is collapsed
181 * @event panelcollapse
182 * @param {Ext.ux.InfoPanel} panel
183 */
184 panelcollapse: true
185
186 /**
187 * Fires when a panel of the dock is expanded
188 * @event panelexpand
189 * @param {Ext.ux.InfoPanel} panel
190 */
191 , panelexpand: true
192
193 /**
194 * Fires when a panel of the dock is pinned
195 * @event panelpinned
196 * @param {Ext.ux.InfoPanel} panel
197 * @param {Boolean} pinned true if panel was pinned false if unpinned
198 */
199 , panelpinned: true
200
201 /**
202 * Fires when the independent state of dock changes
203 * @event independent
204 * @param {Ext.ux.Accordion} this
205 * @param {Boolean} independent New independent state
206 */
207 , independent: true
208
209 /**
210 * Fires when the order of panel is changed
211 * @event orderchange
212 * @param {Ext.ux.Accordion} this
213 * @param {Array} order New order array
214 */
215 , orderchange: true
216
217 /**
218 * Fires when the undockable state of dock changes
219 * @event undockable
220 * @param {Ext.ux.Accordion} this
221 * @param {Array} undockable New undockable state
222 */
223 , undockable: true
224
225 /**
226 * Fires when a panel is undocked
227 * @event panelundock
228 * @param {Ext.ux.InfoPanel} panel
229 * @param {Object} box Position and size object
230 */
231 , panelundock: true
232
233 /**
234 * Fires when a panel is undocked
235 * @event paneldock
236 * @param {Ext.ux.InfoPanel} panel
237 */
238 , paneldock: true
239
240 /**
241 * Fires when a panel box is changed, e.g. after dragging
242 * @event panelbox
243 * @param {Ext.ux.InfoPanel} panel
244 * @param {Object} box Position and size object
245 */
246 , panelbox: true
247
248 /**
249 * Fires when useShadow status changes
250 * @event useshadow
251 * @param {Ext.ux.Accordion} this
252 * @param {Boolean} shadow Use shadow (for undocked panels) flag
253 */
254 , useshadow: true
255
256 /**
257 * Fires before the panel is detached from this accordion. Return false to cancel the detach
258 * @event beforedetach
259 * @param {Ext.ux.Accordion} this
260 * @param {Ext.ux.InfoPanel} panel being detached
261 */
262 , beforedetach: true
263
264 /**
265 * Fires after the panel has been detached from this accordion
266 * @event detach
267 * @param {Ext.ux.Accordion} this
268 * @param {Ext.ux.InfoPanel} panel detached panel
269 */
270 , detach: true
271
272 /**
273 * Fires before the panel is attached from this accordion. Return false to cancel the attach
274 * @event beforeattach
275 * @param {Ext.ux.Accordion} this
276 * @param {Ext.ux.InfoPanel} panel being attached
277 */
278 , beforeattach: true
279
280 /**
281 * Fires after the panel is attached to this accordion
282 * @event attach
283 * @param {Ext.ux.Accordion} this
284 * @param {Ext.ux.InfoPanel} panel attached panel
285 */
286 , attach: true
287
288 });
289 // }}}
290
291 // setup body
292 this.body = Ext.get(this.body) || this.el;
293 this.resizeEl = this.body;
294 this.id = this.id || this.body.id;
295 this.body.addClass('x-dock-body');
296
297 // setup desktop
298 this.desktop = Ext.get(this.desktop || document.body);
299 //this.desktop = this.desktop.dom || this.desktop;
300
301 // setup fixed hight
302 this.wrapEl = Ext.get(this.wrapEl);
303 if(this.fitHeight) {
304 this.body.setStyle('overflow', 'hidden');
305 // this.bodyHeight = this.initialHeight || this.body.getHeight();
306 this.body.setHeight(this.initialHeight || this.body.getHeight());
307 if(this.boxWrap && this.wrapEl) {
308 this.wrapEl.boxWrap();
309 }
310 }
311
312 // watch window resize
313 if(this.monitorWindowResize) {
314 Ext.EventManager.onWindowResize(this.adjustViewport, this);
315 }
316
317 // create drop zone for panels
318 this.dd = new Ext.dd.DropZone(this.body.dom, {
319 ddGroup: this.ddGroup || 'dock-' + this.id
320 });
321
322 Ext.ux.AccordionManager.add(this);
323
324 }; // end of constructor
325
326 // extend
327 Ext.extend(Ext.ux.Accordion, Ext.ContentPanel, {
328
329 // {{{
330 // defaults
331 independent: false
332 , undockable: true
333 , useShadow: true
334 , boxWrap: false
335 , fitHeight: false
336 , initialHeight: 0
337 , animate: true // global animation flag
338 , expandCount: 0
339 , expanding: false
340 , monitorWindowResize: true
341 , resizable: true // global resizable flag
342 , draggable: true // global draggable flag
343 , forceOrder: false
344 , keepState: true
345 , hideOtherOnExpand: false
346 // }}}
347 // {{{
348 /**
349 * Adds the panel to Accordion
350 * @param {Ext.ux.InfoPanel} panel Panel to add
351 * @return {Ext.ux.InfoPanel} added panel
352 */
353 , add: function(panel) {
354
355 // append panel to body
356 this.body.appendChild(panel.el);
357
358 this.attach(panel);
359
360 // panel dragging
361 if(undefined === panel.draggable && this.draggable) {
362 panel.draggable = true;
363 panel.dd = new Ext.ux.Accordion.DDDock(panel, this.ddGroup || 'dock-' + this.id, this);
364 }
365
366 // panel resizing
367 if(undefined === panel.resizable && this.resizable) {
368 panel.resizable = true;
369 // panel.setResizable(true);
370 }
371
372 // panel shadow
373 panel.useShadow = undefined === panel.useShadow ? this.useShadow : panel.useShadow;
374 panel.setShadow(panel.useShadow);
375 if(panel.shadow) {
376 panel.shadow.hide();
377 }
378
379 // panel animation
380 panel.animate = undefined === panel.animate ? this.animate : panel.animate;
381
382 // z-index for panel
383 panel.zindex = Ext.ux.AccordionManager.getNextZindex();
384
385 panel.docked = true;
386 panel.desktop = this.desktop;
387
388 if(false === panel.collapsed) {
389 panel.collapsed = true;
390 panel.expand(true);
391 }
392 return panel;
393
394 }
395 // }}}
396 // {{{
397 /**
398 * attach panel to this accordion
399 * @param {Ext.ux.InfoPanel} panel panel to attach
400 * @return {Ext.ux.Accordion} this
401 */
402 , attach: function(panel) {
403
404 // fire beforeattach event
405 if(false === this.fireEvent('beforeattach', this, panel)) {
406 return this;
407 }
408
409 // add panel to items
410 this.items.add(panel.id, panel);
411
412 // install event handlers
413 this.installRelays(panel);
414 panel.bodyClickDelegate = this.onClickPanelBody.createDelegate(this, [panel]);
415 panel.body.on('click', panel.bodyClickDelegate);
416
417 // set panel dock
418 panel.dock = this;
419
420 // add docked class to panel body
421 panel.body.replaceClass('x-dock-panel-body-undocked', 'x-dock-panel-body-docked');
422
423 // repair panel height
424 panel.autoSize();
425 if(this.fitHeight) {
426 this.setPanelHeight(panel);
427 }
428
429 // fire attach event
430 this.fireEvent('attach', this, panel);
431
432 return this;
433 }
434 // }}}
435 // {{{
436 /**
437 * detach panel from this accordion
438 * @param {Ext.ux.InfoPanel} panel to detach
439 * @return {Ext.ux.Accordion} this
440 */
441 , detach: function(panel) {
442
443 // fire beforedetach event
444 if(false === this.fireEvent('beforedetach', this, panel)) {
445 return this;
446 }
447
448 // unhook events from panel
449 this.removeRelays(panel);
450 panel.body.un('click', panel.bodyClickDelegate);
451
452 // remove panel from items
453 this.items.remove(panel);
454 panel.dock = null;
455
456 // remove docked class from panel body
457 panel.body.replaceClass('x-dock-panel-body-docked', 'x-dock-panel-body-undocked');
458
459 // repair expanded property
460 if(this.expanded === panel) {
461 this.expanded = null;
462 }
463
464 // repair panel height
465 panel.autoSize();
466 if(this.fitHeight) {
467 this.setPanelHeight();
468 }
469
470 // fire detach event
471 this.fireEvent('detach', this, panel);
472
473 return this;
474 }
475 // }}}
476 // {{{
477 /**
478 * Called internally to raise panel above others
479 * @param {Ext.ux.InfoPanel} panel Panel to raise
480 * @return {Ext.ux.InfoPanel} panel Panel that has been raised
481 */
482 , raise: function(panel) {
483 return Ext.ux.AccordionManager.raise(panel);
484 }
485 // }}}
486 // {{{
487 /**
488 * Resets the order of panels within the dock
489 *
490 * @return {Ext.ux.Accordion} this
491 */
492 , resetOrder: function() {
493 this.items.each(function(panel) {
494 if(!panel.docked) {
495 return;
496 }
497 this.body.appendChild(panel.el);
498 }, this);
499 this.updateOrder();
500 return this;
501 }
502 // }}}
503 // {{{
504 /**
505 * Called internally to update the order variable after dragging
506 */
507 , updateOrder: function() {
508 var order = [];
509 var titles = this.body.select('div.x-layout-panel-hd');
510 titles.each(function(titleEl) {
511 order.push(titleEl.dom.parentNode.id);
512 });
513 this.order = order;
514 this.fireEvent('orderchange', this, order);
515 }
516 // }}}
517 // {{{
518 /**
519 * Returns array of panel ids in the current order
520 * @return {Array} order of panels
521 */
522 , getOrder: function() {
523 return this.order;
524 }
525 // }}}
526 // {{{
527 /**
528 * Set the order of panels
529 * @param {Array} order Array of ids of panels in required order.
530 * @return {Ext.ux.Accordion} this
531 */
532 , setOrder: function(order) {
533 if('object' !== typeof order || undefined === order.length) {
534 throw "setOrder: Argument is not array.";
535 }
536 var panelEl, dock, panelId, panel;
537 for(var i = 0; i < order.length; i++) {
538 panelId = order[i];
539 dock = Ext.ux.AccordionManager.get(panelId);
540 if(dock && dock !== this) {
541 panel = dock.items.get(panelId);
542 dock.detach(panel);
543 this.attach(panel);
544 }
545 panelEl = Ext.get(panelId);
546 if(panelEl) {
547 this.body.appendChild(panelEl);
548 }
549 }
550 this.updateOrder();
551 return this;
552 }
553 // }}}
554 // {{{
555 /**
556 * Collapse all docked panels
557 * @param {Boolean} alsoPinned true to first unpin then collapse
558 * @param {Ext.ux.InfoPanel} except This panel will not be collapsed.
559 * @return {Ext.ux.Accordion} this
560 */
561 , collapseAll: function(alsoPinned, except) {
562 this.items.each(function(panel) {
563 if(panel.docked) {
564 panel.pinned = alsoPinned ? false : panel.pinned;
565 if(!except || panel !== except) {
566 panel.collapse();
567 }
568 }
569 }, this);
570 return this;
571 }
572 // }}}
573 // {{{
574 /**
575 * Expand all docked panels in independent mode
576 * @return {Ext.ux.Accordion} this
577 */
578 , expandAll: function() {
579 if(this.independent) {
580 this.items.each(function(panel) {
581 if(panel.docked && panel.collapsed) {
582 panel.expand();
583 }
584 }, this);
585 }
586 }
587 // }}}
588 // {{{
589 /**
590 * Called internally while dragging and by state manager
591 * @param {Ext.ux.InfoPanel/String} panel Panel object or id of the panel
592 * @box {Object} box coordinates with target position and size
593 * @return {Ext.ux.Accordion} this
594 */
595 , undock: function(panel, box) {
596
597 // get panel if necessary
598 panel = 'string' === typeof panel ? this.items.get(panel) : panel;
599
600 // proceed only if we have docked panel and in undockable mode
601 if(panel && panel.docked && this.undockable) {
602
603 // sanity check
604 if(box.x < 0 || box.y < 0) {
605 return this;
606 }
607
608 // todo: check this
609 // if(panel.collapsed) {
610 // box.height = panel.lastHeight || panel.maxHeight || box.height;
611 // }
612
613 // move the panel in the dom (append to desktop)
614 this.desktop.appendChild(panel.el.dom);
615
616 // adjust panel visuals
617 panel.el.applyStyles({
618 position:'absolute'
619 , 'z-index': panel.zindex
620 });
621 panel.body.replaceClass('x-dock-panel-body-docked', 'x-dock-panel-body-undocked');
622
623 // position the panel
624 panel.setBox(box);
625
626 // reset docked flag
627 panel.docked = false;
628
629 // hide panel shadow (will be shown by raise)
630 if(panel.shadow) {
631 panel.shadow.hide();
632 }
633
634 // raise panel above others
635 this.raise(panel);
636
637 panel.autoSize();
638
639 if(panel === this.expanded) {
640 this.expanded = null;
641 }
642
643 // set the height of a docked expanded panel
644 this.setPanelHeight(this.expanded);
645
646 // enable resizing and scrolling
647 panel.setResizable(!panel.collapsed);
648
649 // remember size of the undocked panel
650 panel.lastWidth = box.width;
651 // panel.lastHeight = box.height;
652
653 // fire panelundock event
654 this.fireEvent('panelundock', panel, {x:box.x, y:box.y, width:box.width, height:box.height});
655
656 // this.updateOrder();
657 }
658
659 return this;
660 }
661 // }}}
662 // {{{
663 /**
664 * Called internally while dragging
665 * @param {Ext.ux.InfoPanel/String} panel Panel object or id of the panel
666 * @param {String} targetId id of panel after which this panel will be docked
667 * @return {Ext.ux.Accordion} this
668 */
669 , dock: function(panel, targetId) {
670
671 // get panel if necessary
672 panel = 'string' === typeof panel ? this.items.get(panel) : panel;
673
674 // proceed only if we have a docked panel
675 var dockWidth, newTargetId, panelHeight, idx, i, targetPanel;
676 if(panel && !panel.docked) {
677
678 // find correct target if order is forced
679 if(this.forceOrder) {
680 idx = this.items.indexOf(panel);
681 for(i = idx + 1; i < this.items.getCount(); i++) {
682 targetPanel = this.items.itemAt(i);
683 if(targetPanel.docked) {
684 newTargetId = targetPanel.id;
685 break;
686 }
687 }
688 targetId = newTargetId || this.id;
689 }
690
691 // remember width and height
692 if(!panel.collapsed) {
693 // panel.lastWidth = panel.el.getWidth();
694 // panel.lastHeight = panel.el.getHeight();
695 if(!this.independent && this.expanded) {
696 this.expanded.collapse();
697 }
698 this.expanded = panel;
699 }
700
701 dockWidth = this.body.getWidth(true);
702
703 // move the panel element in the dom
704 if(targetId && (this.body.id !== targetId)) {
705 panel.el.insertBefore(Ext.fly(targetId));
706 }
707 else {
708 panel.el.appendTo(this.body);
709 }
710
711 // set docked flag
712 panel.docked = true;
713
714 // adjust panel visuals
715 panel.body.replaceClass('x-dock-panel-body-undocked', 'x-dock-panel-body-docked');
716 panel.el.applyStyles({
717 top:''
718 , left:''
719 , width:''
720 // , height:''
721 , 'z-index':''
722 , position:'relative'
723 , visibility:''
724 });
725 panel.body.applyStyles({width: Ext.isIE ? dockWidth + 'px' : '', height:''});
726
727 panel.autoSize();
728 // if(!this.fitHeight) {
729 // panelHeight = panel.fixedHeight || panel.maxHeight;
730 // if(panelHeight) {
731 // panel.setHeight(panelHeight);
732 // }
733 // }
734
735 // disable resizing and shadow
736 panel.setResizable(false);
737 if(panel.shadow) {
738 panel.shadow.hide();
739 }
740
741 // set panel height (only if this.fitHeight = true)
742 this.setPanelHeight(panel.collapsed ? this.expanded : panel);
743
744 // fire paneldock event
745 this.fireEvent('paneldock', panel);
746
747 // this.updateOrder();
748 }
749
750 return this;
751 }
752 // }}}
753 // {{{
754 /**
755 * Moves panel from this dock (accordion) to another
756 * @param {Ext.ux.InfoPanel} panel Panel to move
757 * @param {Ext.ux.Accordion} targetDock Dock to move to
758 */
759 , moveToDock: function(panel, targetDock) {
760 this.detach(panel);
761 targetDock.attach(panel);
762 panel.docked = false;
763 targetDock.dock(panel);
764 this.setPanelHeight();
765 this.updateOrder();
766 targetDock.updateOrder();
767 }
768 // }}}
769 // {{{
770 /**
771 * Sets the independent mode
772 * @param {Boolean} independent set to false for normal mode
773 * @return {Ext.ux.Accordion} this
774 */
775 , setIndependent: function(independent) {
776 this.independent = independent ? true : false;
777 this.fireEvent('independent', this, independent);
778 return this;
779 }
780 // }}}
781 // {{{
782 /**
783 * Sets the undockable mode
784 * If undockable === true all undocked panels are docked and collapsed (except pinned)
785 * @param {Boolean} undockable set to true to not allow undocking
786 * @return {Ext.ux.Accordion} this
787 */
788 , setUndockable: function(undockable) {
789 this.items.each(function(panel) {
790
791 // dock and collapse (except pinned) all undocked panels if not undockable
792 if(!undockable && !panel.docked) {
793 this.dock(panel);
794 if(!this.independent && !panel.collapsed && !panel.pinned) {
795 panel.collapse();
796 }
797 }
798
799 // refresh dragging constraints
800 if(panel.docked && panel.draggable) {
801 panel.dd.constrainTo(this.body, 0, false);
802 panel.dd.clearConstraints();
803 if(undockable) {
804 panel.constrainToDesktop();
805 }
806 else {
807 panel.dd.setXConstraint(0,0);
808 }
809 }
810 }, this);
811
812 // set the flag and fire event
813 this.undockable = undockable;
814 this.fireEvent('undockable', this, undockable);
815 return this;
816 }
817 // }}}
818 // {{{
819 /**
820 * Sets the shadows for all panels
821 * @param {Boolean} shadow set to false to disable shadows
822 * @return {Ext.ux.Accordion} this
823 */
824 , setShadow: function(shadow) {
825 this.items.each(function(panel) {
826 panel.useShadow = shadow;
827 panel.setShadow(false);
828 if(!panel.docked) {
829 panel.setShadow(shadow);
830 }
831 });
832 this.useShadow = shadow;
833 this.fireEvent('useshadow', this, shadow);
834 return this;
835 }
836 // }}}
837 // {{{
838 /**
839 * Called when user clicks the panel body
840 * @param {Ext.ux.InfoPanel} panel
841 */
842 , onClickPanelBody: function(panel) {
843 if(!panel.docked) {
844 this.raise(panel);
845 }
846 }
847 // }}}
848 // {{{
849 /**
850 * Called internally for fixed height docks to get current height of panel(s)
851 */
852 , getPanelBodyHeight: function() {
853 var titleHeight = 0;
854 this.items.each(function(panel) {
855 titleHeight += panel.docked ? panel.titleEl.getHeight() : 0;
856 });
857 this.panelBodyHeight = this.body.getHeight() - titleHeight - this.body.getFrameWidth('tb') + 1;
858 // this.panelBodyHeight = this.body.getHeight() - titleHeight - this.body.getFrameWidth('tb');
859 return this.panelBodyHeight;
860 }
861 // }}}
862 // {{{
863 /**
864 * Sets the height of panel body
865 * Used with fixed height (fitHeight:true) docs
866 * @param {Ext.ux.InfoPanel} panel (defaults to this.expanded)
867 * @return {Ext.ux.Accordion} this
868 */
869 , setPanelHeight: function(panel) {
870 panel = panel || this.expanded;
871 if(this.fitHeight && panel && panel.docked) {
872 panel.body.setHeight(this.getPanelBodyHeight());
873 panel.setHeight(panel.getHeight());
874 }
875 return this;
876 }
877 // }}}
878 // {{{
879 /**
880 * Constrains the dragging of panels do the desktop
881 * @return {Ext.ux.Accordion} this
882 */
883 , constrainToDesktop: function() {
884 this.items.each(function(panel) {
885 panel.constrainToDesktop();
886 }, this);
887 return this;
888 }
889 // }}}
890 // {{{
891 /**
892 * Clears dragging constraints of panels
893 * @return {Ext.ux.Accordion} this
894 */
895 , clearConstraints: function() {
896 this.items.each(function(panel) {
897 panel.dd.clearConstraints();
898 });
899 }
900 // }}}
901 // {{{
902 /**
903 * Shows all panels
904 * @param {Boolean} show (optional) if false hides the panels instead of showing
905 * @param {Boolean} alsoUndocked show also undocked panels (defaults to false)
906 * @return {Ext.ux.Accordion} this
907 */
908 , showAll: function(show, alsoUndocked) {
909 show = (false === show ? false : true);
910 this.items.each(function(panel) {
911 panel.show(show, alsoUndocked);
912 });
913 return this;
914 }
915 // }}}
916
917 , showOther: function(panel, show, alsoPinned) {
918 show = (false === show ? false : true);
919 this.items.each(function(p) {
920 if(p === panel || (p.pinned && !alsoPinned)) {
921 return;
922 }
923 if(show) {
924 p.show();
925 }
926 else {
927 p.hide();
928 }
929 });
930 }
931
932 , hideOther: function(panel, alsoPinned) {
933 this.showOther(panel, false, alsoPinned);
934 }
935
936 // {{{
937 /**
938 * Hides all panels
939 * @param {Boolean} alsoUndocked hide also undocked panels (defaults to false)
940 * @return {Ext.ux.Accordion} this
941 */
942 , hideAll: function(alsoUndocked) {
943 return this.showAll(false, alsoUndocked);
944 }
945 // }}}
946 // {{{
947 /**
948 * Called internally to disable/enable scrolling of the dock while animating
949 * @param {Boolean} enable true to enable, false to disable
950 * @return {void}
951 * @todo not used at present - revise
952 */
953 , setDockScroll: function(enable) {
954 if(enable && !this.fitHeight) {
955 this.body.setStyle('overflow','auto');
956 }
957 else {
958 this.body.setStyle('overflow','hidden');
959 }
960 }
961 // }}}
962 // {{{
963 /**
964 * Set Accordion size
965 * Overrides ContentPanel.setSize
966 *
967 * @param {Integer} w width
968 * @param {Integer} h height
969 * @return {Ext.ux.Accordion} this
970 */
971 , setSize: function(w, h) {
972 // call parent's setSize
973 Ext.ux.Accordion.superclass.setSize.call(this, w, h);
974 // this.body.setHeight(h);
975 this.setPanelHeight();
976
977 return this;
978 }
979 // }}}
980 // {{{
981 /**
982 * Called as windowResize event handler
983 *
984 * @todo: review
985 */
986 , adjustViewport: function() {
987 var viewport = this.desktop.dom === document.body ? {} : Ext.get(this.desktop).getBox();
988
989 viewport.height =
990 this.desktop === document.body
991 ? window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
992 : viewport.height
993 ;
994
995 viewport.width =
996 this.desktop === document.body
997 ? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
998 : viewport.width
999 ;
1000
1001 viewport.x = this.desktop === document.body ? 0 : viewport.x;
1002 viewport.y = this.desktop === document.body ? 0 : viewport.y;
1003
1004 this.items.each(function(panel) {
1005 if(!panel.docked) {
1006 panel.moveToViewport(viewport);
1007 }
1008 });
1009
1010 }
1011 // }}}
1012 // {{{
1013 /**
1014 * private - called internally to create relay event function
1015 * @param {String} ename event name to relay
1016 * @return {Function} relay event function
1017 */
1018 , createRelay: function(ename) {
1019 return function() {
1020 return this.fireEvent.apply(this, Ext.combine(ename, Array.prototype.slice.call(arguments, 0)));
1021 };
1022 }
1023 // }}}
1024 // {{{
1025 /**
1026 * Array of event names to relay
1027 */
1028 , relayedEvents: [
1029 'beforecollapse'
1030 , 'collapse'
1031 , 'beforeexpand'
1032 , 'expand'
1033 , 'animationcompleted'
1034 , 'pinned'
1035 , 'boxchange'
1036 , 'destroy'
1037 ]
1038 // }}}
1039 // {{{
1040 /**
1041 * private - called internaly to install event relays on panel
1042 * @param {Ext.ux.InfoPanel} panel panel to install events on
1043 */
1044 , installRelays: function(panel) {
1045 panel.relays = {};
1046 var ename, fn;
1047 for(var i = 0; i < this.relayedEvents.length; i++) {
1048 ename = this.relayedEvents[i];
1049 fn = this.createRelay(ename);
1050 panel.relays[ename] = fn;
1051 panel.on(ename, fn, this);
1052 }
1053 }
1054 // }}}
1055 // {{{
1056 /**
1057 * private - called internaly to remove installed relays
1058 * @param {Ext.ux.InfoPanel} panel panel to remove relays from
1059 */
1060 , removeRelays: function(panel) {
1061 for(var ename in panel.relays) {
1062 panel.un(ename, panel.relays[ename], this);
1063 }
1064 panel.relays = {};
1065 }
1066 // }}}
1067 // {{{
1068 /**
1069 * Removes and destroys panel
1070 * @param {String/InfoPanel} panel Panel object or id
1071 */
1072 , remove: function(panel) {
1073 panel = this.items.get(panel.id || panel);
1074 if(panel) {
1075 this.detach(panel);
1076 panel.destroy();
1077 }
1078 }
1079 // }}}
1080 // {{{
1081 /**
1082 * Removes and destroys all panels
1083 */
1084 , removeAll: function() {
1085 this.items.each(function(panel) {
1086 this.remove(panel);
1087 }, this);
1088 }
1089 // }}}
1090 // {{{
1091 /**
1092 * Destroys Accrodion
1093 */
1094 , destroy: function() {
1095 this.removeAll();
1096 Ext.ux.Accordion.superclass.destroy.call(this);
1097 }
1098 // }}}
1099
1100 }); // end of extend
1101
1102 // {{{
1103 // {{{
1104 /**
1105 * @class Ext.ux.Accordion.DDDock
1106 * @constructor
1107 * @extends Ext.dd.DDProxy
1108 * @param {Ext.ux.InfoPanel} panel Panel the dragging object is created for
1109 * @param {String} group Only elements of same group interact
1110 * @param {Ext.ux.Accordion} dock Place where panels are docked/undocked
1111 */
1112 Ext.ux.Accordion.DDDock = function(panel, group, dock) {
1113
1114 // call parent constructor
1115 Ext.ux.Accordion.DDDock.superclass.constructor.call(this, panel.el.dom, group);
1116
1117 // save panel and dock references for use in methods
1118 this.panel = panel;
1119 this.dock = dock;
1120
1121 // drag by grabbing the title only
1122 this.setHandleElId(panel.titleEl.id);
1123
1124 // move only in the dock if undockable
1125 if(false === dock.undockable) {
1126 this.setXConstraint(0, 0);
1127 }
1128
1129 // init internal variables
1130 this.lastY = 0;
1131
1132 //this.DDM.mode = Ext.dd.DDM.INTERSECT;
1133 this.DDM.mode = Ext.dd.DDM.POINT;
1134
1135 }; // end of constructor
1136 // }}}
1137
1138 // extend
1139 Ext.extend(Ext.ux.Accordion.DDDock, Ext.dd.DDProxy, {
1140
1141 // {{{
1142 /**
1143 * Default DDProxy startDrag override
1144 * Saves some variable for use by other methods
1145 * and creates nice dragging proxy (ghost)
1146 *
1147 * Passed x, y arguments are not used
1148 */
1149 startDrag: function(x, y) {
1150
1151 this.createIframeMasks();
1152
1153 this.lastMoveTarget = null;
1154
1155 // create nice dragging ghost
1156 this.createGhost();
1157
1158 // get srcEl (the original) and dragEl (the ghost)
1159 var srcEl = Ext.get(this.getEl());
1160 var dragEl = Ext.get(this.getDragEl());
1161
1162 // refresh constraints
1163 this.panel.constrainToDesktop();
1164 var dragHeight, rightC, bottomC;
1165 if(this.panel.dock.undockable) {
1166 if(this.panel.collapsed) {
1167 dragHeight = this.panel.titleEl.getHeight();
1168 }
1169 else {
1170 dragHeight = dragEl.getHeight();
1171 dragHeight = dragHeight <= this.panel.titleEl.getHeight() ? srcEl.getHeight() : dragHeight;
1172 }
1173
1174 rightC = this.rightConstraint + srcEl.getWidth() - dragEl.getWidth();
1175 bottomC = this.bottomConstraint + srcEl.getHeight() - dragHeight;
1176 this.setXConstraint(this.leftConstraint, rightC);
1177 this.setYConstraint(this.topConstraint, bottomC);
1178 }
1179 else {
1180 if(this.panel.docked) {
1181 this.setXConstraint(0, 0);
1182 }
1183 }
1184
1185 // hide dragEl (will be shown by onDrag)
1186 dragEl.hide();
1187
1188 // raise panel's "window" above others
1189 if(!this.panel.docked) {
1190 this.panel.dock.raise(this.panel);
1191 }
1192
1193 // hide panel's shadow if any
1194 this.panel.setShadow(false);
1195
1196 // clear visibility of panel's body (was setup by animations)
1197 this.panel.body.dom.style.visibility = '';
1198
1199 // hide source panel if undocked
1200 if(!this.panel.docked) {
1201 // srcEl.hide();
1202 srcEl.setDisplayed(false);
1203 dragEl.show();
1204 }
1205
1206 } // end of function startDrag
1207 // }}}
1208 // {{{
1209 /**
1210 * Called internally to create nice dragging proxy (ghost)
1211 */
1212 , createGhost: function() {
1213
1214 // get variables
1215 var srcEl = Ext.get(this.getEl());
1216 var dragEl = Ext.get(this.getDragEl());
1217 var panel = this.panel;
1218 var dock = panel.dock;
1219
1220 // adjust look of ghost
1221 var am = Ext.ux.AccordionManager;
1222 dragEl.addClass('x-dock-panel-ghost');
1223 dragEl.applyStyles({border:'1px solid #84a0c4','z-index': am.zindex + am.zindexInc});
1224
1225 // set size of ghost same as original
1226 dragEl.setBox(srcEl.getBox());
1227 if(panel.docked) {
1228 if(panel.lastWidth && dock.undockable) {
1229 dragEl.setWidth(panel.lastWidth);
1230 }
1231 if(!panel.collapsed && dock.undockable && (panel.lastHeight > panel.titleEl.getHeight())) {
1232 dragEl.setHeight(panel.lastHeight);
1233 }
1234 }
1235
1236 // remove unnecessary text nodes from srcEl
1237 srcEl.clean();
1238
1239 // setup title
1240 var dragTitleEl = Ext.DomHelper.append(dragEl, {tag:'div'}, true);
1241 dragTitleEl.update(srcEl.dom.firstChild.innerHTML);
1242 dragTitleEl.dom.className = srcEl.dom.firstChild.className;
1243 if(panel.collapsed && Ext.isIE) {
1244 dragTitleEl.dom.style.borderBottom = "0";
1245 }
1246
1247 } // end of function createGhost
1248 // }}}
1249 // {{{
1250 /**
1251 * Default DDProxy onDragOver override
1252 * It is called when dragging over a panel
1253 * or over the dock.body DropZone
1254 *
1255 * @param {Event} e not used
1256 * @param {String} targetId id of the target we're over
1257 *
1258 * Beware: While dragging over docked panels it's called
1259 * twice. Once for panel and once for DropZone
1260 */
1261 , onDragOver: function(e, targetId) {
1262
1263 // get panel element
1264 var srcEl = Ext.get(this.getEl());
1265
1266 // get target panel and dock
1267 var targetDock = Ext.ux.AccordionManager.get(targetId);
1268 var targetPanel = targetDock ? targetDock.items.get(targetId) : this.panel;
1269
1270 // setup current target for endDrag
1271 if(targetPanel) {
1272 this.currentTarget = targetPanel.id;
1273 }
1274 if(targetDock && !this.currentTarget) {
1275 this.currentTarget = targetDock.id;
1276 }
1277
1278 // landing indicators
1279 if(targetPanel && targetPanel.docked && !this.panel.dock.forceOrder) {
1280 targetPanel.titleEl.addClass('x-dock-panel-title-dragover');
1281 }
1282 if(targetDock) {
1283 targetDock.body.addClass('x-dock-body-dragover');
1284 }
1285 if(this.panel.docked) {
1286 this.panel.titleEl.addClass('x-dock-panel-title-dragover');
1287 }
1288
1289 // reorder panels in dock if we're docked too
1290 var targetEl;
1291
1292 if(targetDock === this.panel.dock
1293 && targetPanel
1294 && targetPanel.docked
1295 && this.panel.docked
1296 && !this.panel.dock.forceOrder) {
1297 targetEl = targetPanel.el;
1298
1299 if(targetPanel.collapsed || this.lastMoveTarget !== targetPanel) {
1300 if(this.movingUp) {
1301 srcEl.insertBefore(targetEl);
1302 this.lastMoveTarget = targetPanel;
1303 }
1304 else {
1305 srcEl.insertAfter(targetEl);
1306 this.lastMoveTarget = targetPanel;
1307 }
1308 }
1309 this.DDM.refreshCache(this.groups);
1310 }
1311
1312 } // end of function onDragOver
1313 // }}}
1314 // {{{
1315 /**
1316 * called internally to attach this.panel to accordion
1317 * @param {Ext.ux.Accordion} targetDock the dock to attach the panel to
1318 */
1319 , attachToDock: function(targetDock) {
1320 if(targetDock && this.panel.dock !== targetDock) {
1321 // detach panel
1322 this.panel.dock.detach(this.panel);
1323
1324 // attach panel
1325 targetDock.attach(this.panel);
1326
1327 }
1328 }
1329 // }}}
1330 // {{{
1331 /**
1332 * Called internally when cursor leaves a drop target
1333 * @param {Ext.Event} e
1334 * @param {String} targetId id of target we're leaving
1335 */
1336 , onDragOut: function(e, targetId) {
1337
1338 var targetDock = Ext.ux.AccordionManager.get(targetId);
1339 var targetPanel = targetDock ? targetDock.items.get(targetId) : this.panel;
1340
1341 if(targetDock) {
1342 targetDock.body.removeClass('x-dock-body-dragover');
1343 }
1344
1345 if(targetPanel) {
1346 targetPanel.titleEl.removeClass('x-dock-panel-title-dragover');
1347 }
1348 this.currentTarget = null;
1349 }
1350 // }}}
1351 // {{{
1352 /**
1353 * Default DDProxy onDrag override
1354 *
1355 * It's called while dragging
1356 * @param {Event} e used to get coordinates
1357 */
1358 , onDrag: function(e) {
1359
1360 // get source (original) and proxy (ghost) elements
1361 var srcEl = Ext.get(this.getEl());
1362 var dragEl = Ext.get(this.getDragEl());
1363
1364 if(!dragEl.isVisible()) {
1365 dragEl.show();
1366 }
1367
1368 var y = e.getPageY();
1369
1370 this.movingUp = this.lastY > y;
1371 this.lastY = y;
1372
1373 } // end of function onDrag
1374 // }}}
1375 // {{{
1376 /**
1377 * Default DDProxy endDrag override
1378 *
1379 * Called when dragging is finished
1380 */
1381 , endDrag: function() {
1382
1383 this.destroyIframeMasks();
1384
1385 // get the source (original) and proxy (ghost) elements
1386 var srcEl = Ext.get(this.getEl());
1387 var dragEl = Ext.get(this.getDragEl());
1388
1389 srcEl.setDisplayed(true);
1390
1391 // get box and hide the ghost
1392 var box = dragEl.getBox();
1393
1394 var sourceDock = this.panel.dock;
1395 var targetDock = Ext.ux.AccordionManager.get(this.currentTarget);
1396 var targetPanel = targetDock ? targetDock.items.get(this.currentTarget) : this.panel;
1397 var orderChanged = false;
1398
1399 // remove any dragover classes from panel title and dock
1400 this.panel.titleEl.removeClass('x-dock-panel-title-dragover');
1401 this.dock.body.removeClass('x-dock-body-dragover');
1402 if(targetDock) {
1403 targetDock.items.each(function(panel) {
1404 panel.titleEl.removeClass('x-dock-panel-title-dragover');
1405 });
1406 }
1407
1408 // undock (docked panel dropped out of dock)
1409 if(!this.panel.dock.catchPanels && (this.panel.docked && !this.currentTarget && !targetDock) || (targetPanel && !targetPanel.docked)) {
1410 this.dock.undock(this.panel, box);
1411 orderChanged = true;
1412 }
1413
1414 // dock undocked panel
1415 else if(!this.panel.docked) {
1416 this.attachToDock(targetDock);
1417 this.panel.dock.dock(this.panel, this.currentTarget);
1418 orderChanged = true;
1419 }
1420
1421 // do nothing for panel moved over it's own dock
1422 // handling has already been done by onDragOver
1423 else if(this.panel.docked && (this.panel.dock === targetDock)) {
1424 // do nothing on purpose - do not remove
1425 orderChanged = true;
1426 }
1427
1428 // dock panel to another dock
1429 else if(this.currentTarget || targetDock) {
1430 this.attachToDock(targetDock);
1431 if(targetDock) {
1432 targetDock.body.removeClass('x-dock-body-dragover');
1433 this.panel.docked = false;
1434 targetDock.dock(this.panel, this.currentTarget);
1435 }
1436 orderChanged = true;
1437 }
1438
1439 // just free dragging
1440 if(!this.panel.docked) {
1441 this.panel.setBox(box);
1442
1443 // let the state manager know the new panel position
1444 this.dock.fireEvent('panelbox', this.panel, {x:box.x, y:box.y, width:box.width, height:box.height});
1445 }
1446
1447 // clear the ghost content, hide id and move it off screen
1448 dragEl.hide();
1449 dragEl.update('');
1450 dragEl.applyStyles({
1451 top:'-9999px'
1452 , left:'-9999px'
1453 , height:'0px'
1454 , width:'0px'
1455 });
1456
1457 if(orderChanged) {
1458 sourceDock.updateOrder();
1459 if(targetDock && targetDock !== sourceDock) {
1460 targetDock.updateOrder();
1461 }
1462 }
1463 this.DDM.refreshCache(this.groups);
1464
1465 } // end of function endDrag
1466 // }}}
1467 // {{{
1468 , createIframeMasks: function() {
1469 this.destroyIframeMasks();
1470
1471 var masks = [];
1472 var iframes = Ext.get(document.body).select('iframe');
1473 iframes.each(function(iframe) {
1474 var mask = Ext.DomHelper.append(document.body, {tag:'div'}, true);
1475 mask.setBox(iframe.getBox());
1476 masks.push(mask);
1477 });
1478 this.iframeMasks = masks;
1479 }
1480 // }}}
1481 // {{{
1482 , destroyIframeMasks: function() {
1483 if(!this.iframeMasks || ! this.iframeMasks.length) {
1484 return;
1485 }
1486 for(var i = 0; i < this.iframeMasks.length; i++) {
1487 this.iframeMasks[i].remove();
1488 }
1489 this.iframeMasks = [];
1490 }
1491 // }}}
1492
1493 });
1494 // }}}
1495 // {{{
1496 /**
1497 * Private class for keeping and restoring state of the Accordion
1498 */
1499 Ext.ux.AccordionStateManager = function() {
1500 this.state = { docks:{}, panels:{} };
1501 };
1502
1503 Ext.ux.AccordionStateManager.prototype = {
1504 init: function(provider) {
1505
1506 // save state provider
1507 this.provider = provider;
1508 // var state = provider.get('accjs-state');
1509 // if(state) {
1510 // this.state = state;
1511 // }
1512 state = this.state;
1513
1514 var am = Ext.ux.AccordionManager;
1515 var dockState;
1516
1517 // {{{
1518 // docks loop
1519 am.each(function(dock) {
1520 if(false === dock.keepState) {
1521 return;
1522 }
1523
1524 state.docks[dock.id] = provider.get('accjsd-' + dock.id);
1525 dockState = state.docks[dock.id];
1526 if(dockState) {
1527
1528 // {{{
1529 // handle docks (accordions)
1530 if(dockState) {
1531
1532 // {{{
1533 // restore order of panels
1534 if(dockState.order) {
1535 dock.setOrder(dockState.order);
1536 }
1537 // }}}
1538 // {{{
1539 // restore independent
1540 if(undefined !== dockState.independent) {
1541 dock.setIndependent(dockState.independent);
1542 }
1543 // }}}
1544 // {{{
1545 // restore undockable
1546 if(undefined !== dockState.undockable) {
1547 dock.setUndockable(dockState.undockable);
1548 }
1549 // }}}
1550 // {{{
1551 // restore useShadow
1552 if(undefined !== dockState.useShadow) {
1553 dock.setShadow(dockState.useShadow);
1554 }
1555 // }}}
1556
1557 } // end of if(dockState)
1558 // }}}
1559
1560 }
1561
1562 // install event handlers on docks
1563 dock.on({
1564 orderchange: {scope:this, fn:this.onOrderChange}
1565 , independent: {scope:this, fn:this.onIndependent}
1566 , undockable: {scope:this, fn:this.onUndockable}
1567 , useshadow: {scope: this, fn: this.onUseShadow}
1568 , panelexpand: {scope: this, fn: this.onPanelCollapse}
1569 , panelcollapse: {scope: this, fn: this.onPanelCollapse}
1570 , panelpinned: {scope: this, fn: this.onPanelPinned}
1571 , paneldock: {scope: this, fn: this.onPanelUnDock}
1572 , panelundock: {scope: this, fn: this.onPanelUnDock}
1573 , boxchange: {scope: this, fn: this.onPanelUnDock}
1574 , panelbox: {scope: this, fn: this.onPanelUnDock}
1575 });
1576 }, this);
1577 // }}}
1578
1579 // {{{
1580 // panels loop
1581 am.each(function(dock) {
1582 if(!dock.keepState) {
1583 return;
1584 }
1585
1586 // panels within dock loop
1587 var panelState;
1588 dock.items.each(function(panel) {
1589
1590 state.panels[panel.id] = provider.get('accjsp-' + panel.id);
1591 panelState = state.panels[panel.id];
1592
1593 if(panelState) {
1594
1595 // {{{
1596 // restore docked/undocked state
1597 if(undefined !== panelState.docked) {
1598 if(!panelState.docked) {
1599 if('object' === typeof panelState.box) {
1600 panel.docked = true;
1601 panel.dock.undock(panel, panelState.box);
1602 }
1603 }
1604 }
1605 // }}}
1606 // {{{
1607 // restore pinned state
1608 if(undefined !== panelState.pinned) {
1609 panel.pinned = panelState.pinned;
1610 if(panel.pinned) {
1611 panel.expand(true);
1612 }
1613 else {
1614 panel.updateVisuals();
1615 }
1616 }
1617 // }}}
1618 // {{{
1619 // restore collapsed/expanded state
1620 if(undefined !== panelState.collapsed) {
1621 if(panelState.collapsed) {
1622 panel.collapsed = false;
1623 panel.collapse(true);
1624 }
1625 else {
1626 panel.collapsed = true;
1627 panel.expand(true);
1628 }
1629 }
1630 // }}}
1631
1632 }
1633 }, this); // end of panels within dock loop
1634 }, this); // end of docks loop
1635 // }}}
1636
1637
1638 }
1639
1640 // event handlers
1641 // {{{
1642 , onOrderChange: function(dock, order) {
1643 if(false !== dock.keepState) {
1644 this.state.docks[dock.id] = this.state.docks[dock.id] ? this.state.docks[dock.id] : {};
1645 this.state.docks[dock.id].order = order;
1646 this.storeDockState(dock);
1647 }
1648 }
1649 // }}}
1650 // {{{
1651 , onIndependent: function(dock, independent) {
1652 if(false !== dock.keepState) {
1653 this.state.docks[dock.id] = this.state.docks[dock.id] ? this.state.docks[dock.id] : {};
1654 this.state.docks[dock.id].independent = independent;
1655 this.storeDockState(dock);
1656 }
1657 }
1658 // }}}
1659 // {{{
1660 , onUndockable: function(dock, undockable) {
1661 if(false !== dock.keepState) {
1662 this.state.docks[dock.id] = this.state.docks[dock.id] ? this.state.docks[dock.id] : {};
1663 this.state.docks[dock.id].undockable = undockable;
1664 this.storeDockState(dock);
1665 }
1666 }
1667 // }}}
1668 // {{{
1669 , onUseShadow: function(dock, shadow) {
1670 if(false !== dock.keepState) {
1671 this.state.docks[dock.id] = this.state.docks[dock.id] ? this.state.docks[dock.id] : {};
1672 this.state.docks[dock.id].useShadow = shadow;
1673 this.storeDockState(dock);
1674 }
1675 }
1676 // }}}
1677 // {{{
1678 , onPanelCollapse: function(panel) {
1679 if(panel.dock.keepState) {
1680 this.state.panels[panel.id] = this.state.panels[panel.id] || {};
1681 this.state.panels[panel.id].collapsed = panel.collapsed;
1682 }
1683 else {
1684 try {delete(this.state.panels[panel.id].collapsed);}
1685 catch(e){}
1686 }
1687 this.storePanelState(panel);
1688 }
1689 // }}}
1690 // {{{
1691 , onPanelPinned: function(panel, pinned) {
1692 if(panel.dock.keepState) {
1693 this.state.panels[panel.id] = this.state.panels[panel.id] || {};
1694 this.state.panels[panel.id].pinned = pinned;
1695 }
1696 else {
1697 try {delete(this.state.panels[panel.id].pinned);}
1698 catch(e){}
1699 }
1700 this.storePanelState(panel);
1701 }
1702 // }}}
1703 // {{{
1704 , onPanelUnDock: function(panel, box) {
1705 if(panel.dock.keepState) {
1706 this.state.panels[panel.id] = this.state.panels[panel.id] || {};
1707 this.state.panels[panel.id].docked = panel.docked ? true : false;
1708 this.state.panels[panel.id].box = box || null;
1709 }
1710 else {
1711 try {delete(this.state.panels[panel.id].docked);}
1712 catch(e){}
1713 try {delete(this.state.panels[panel.id].box);}
1714 catch(e){}
1715 }
1716 // console.log('onPanelUnDock: ', + panel.id);
1717 this.storePanelState(panel);
1718 }
1719 // }}}
1720 // {{{
1721 , storeDockState: function(dock) {
1722 this.provider.set.defer(700, this, ['accjsd-' + dock.id, this.state.docks[dock.id]]);
1723 }
1724 // }}}
1725 // {{{
1726 , storePanelState: function(panel) {
1727 this.provider.set.defer(700, this, ['accjsp-' + panel.id, this.state.panels[panel.id]]);
1728 }
1729 // }}}
1730
1731 }; // end of Ext.ux.AccordionManager.prototype
1732 // }}}
1733 // {{{
1734 /**
1735 * Singleton to manage multiple accordions
1736 * @singleton
1737 */
1738 Ext.ux.AccordionManager = function() {
1739
1740 // collection of accordions
1741 var items = new Ext.util.MixedCollection();
1742
1743 // public stuff
1744 return {
1745 // starting z-index for panels
1746 zindex: 9999
1747 // z-index increment (2 as 1 is for shadow)
1748 , zindexInc: 2
1749
1750 // {{{
1751 /**
1752 * increments (by this.zindexInc) this.zindex and returns new value
1753 * @return {Integer} next zindex value
1754 */
1755 , getNextZindex: function() {
1756 this.zindex += this.zindexInc;
1757 return this.zindex;
1758 }
1759 // }}}
1760 // {{{
1761 /**
1762 * raises panel above others (in the same desktop)
1763 * Maintains z-index stack
1764 * @param {Ext.ux.InfoPanel} panel panel to raise
1765 * @return {Ext.ux.InfoPanel} panel panel that has been raised
1766 */
1767 , raise: function(panel) {
1768 items.each(function(dock) {
1769 dock.items.each(function(p) {
1770 if(p.zindex > panel.zindex) {
1771 p.zindex -= this.zindexInc;
1772 p.el.applyStyles({'z-index':p.zindex});
1773 if(!p.docked) {
1774 p.setShadow(true);
1775 }
1776 }
1777 }, this);
1778 }, this);
1779
1780 if(panel.zindex !== this.zindex) {
1781 panel.zindex = this.zindex;
1782 panel.el.applyStyles({'z-index':panel.zindex});
1783 if(panel.desktop.lastChild !== panel.el.dom) {
1784 panel.dock.desktop.appendChild(panel.el.dom);
1785 }
1786 if(!panel.docked) {
1787 panel.setShadow(true);
1788 }
1789 }
1790
1791 return panel;
1792 }
1793 // }}}
1794 // {{{
1795 /**
1796 * Adds accordion to items
1797 * @param {Ext.ux.Accordion} acc accordion to add
1798 * @return {Ext.ux.Accordion} added accordion
1799 */
1800 , add: function(acc) {
1801 items.add(acc.id, acc);
1802 return acc;
1803 }
1804 // }}}
1805 // {{{
1806 /**
1807 * get accordion by it's id or by id of some ot it's panels
1808 * @param {String} key id of accordion or panel
1809 * @return {Ext.ux.Accordion} or undefined if not found
1810 */
1811 , get: function(key) {
1812 var dock = items.get(key);
1813 if(!dock) {
1814 items.each(function(acc) {
1815 if(dock) {
1816 return;
1817 }
1818 var panel = acc.items.get(key);
1819 if(panel) {
1820 dock = panel.dock;
1821 }
1822 });
1823 }
1824 return dock;
1825 }
1826 // }}}
1827 // {{{
1828 /**
1829 * get panel by it's id
1830 * @param {String} key id of the panel to get
1831 * @return {Ext.ux.InfoPanel} panel found or null
1832 */
1833 , getPanel: function(key) {
1834 var dock = this.get(key);
1835 return dock && dock.items ? this.get(key).items.get(key) : null;
1836 }
1837 // }}}
1838 // {{{
1839 /**
1840 * Restores state of dock and panels
1841 * @param {Ext.state.Provider} provider (optional) An alternate state provider
1842 */
1843 , restoreState: function(provider) {
1844 if(!provider) {
1845 provider = Ext.state.Manager;
1846 }
1847 var sm = new Ext.ux.AccordionStateManager();
1848 sm.init(provider);
1849
1850 }
1851 // }}}
1852
1853 , each: function(fn, scope) {
1854 items.each(fn, scope);
1855 }
1856
1857 }; // end of return
1858
1859 }();
1860 // }}}
1861
1862 // end of file