1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 sc_require('panes/modal');
  9 
 10 /** @class
 11 
 12   Most SproutCore applications need modal panels. The default way to use the
 13   panel pane is to simply add it to your page like this:
 14 
 15       SC.PanelPane.create({
 16         layout: { width: 400, height: 200, centerX: 0, centerY: 0 },
 17         contentView: SC.View.extend({
 18         })
 19       }).append();
 20 
 21   This will cause your panel to display.  The default layout for a Panel
 22   is to cover the entire document window with a semi-opaque background, and to
 23   resize with the window.
 24 
 25   @extends SC.Pane
 26   @author Erich Ocean
 27   @since SproutCore 1.0
 28 */
 29 SC.PanelPane = SC.Pane.extend(
 30 /** @scope SC.PanelPane.prototype */ {
 31 
 32   /**
 33     Walk like a duck.
 34     @type {Boolean}
 35   */
 36   isPanelPane: YES,
 37 
 38   /**
 39     @type Array
 40     @default ['sc-panel']
 41     @see SC.View#classNames
 42   */
 43   classNames: ['sc-panel'],
 44 
 45   /**
 46     @type Boolean
 47     @default YES
 48     @see SC.Pane#acceptsKeyPane
 49   */
 50   acceptsKeyPane: YES,
 51 
 52   /**
 53     The WAI-ARIA role for panel pane.
 54 
 55     @type String
 56     @default 'dialog'
 57     @constant
 58   */
 59   ariaRole: 'dialog',
 60 
 61   /**
 62     The WAI-ARIA label for the panel. Screen readers will use this to tell
 63     the user a name for the panel.
 64 
 65     @type String
 66   */
 67   ariaLabel: null,
 68 
 69   /**
 70     The WAI-ARIA labelledby for the panel. Screen readers will use this to tell
 71     the header or name of your panel if there is no label. This should be an id
 72     to an element inside the panel.
 73 
 74     @type String
 75   */
 76   ariaLabelledBy: null,
 77 
 78   /**
 79     The WAI-ARIA describedby text. Screen readers will use this to speak the description
 80     of the panel. This should be an id to an element inside the panel.
 81 
 82     @type String
 83   */
 84   ariaDescribedBy: null,
 85 
 86   /**
 87     Indicates that a pane is modal and should not allow clicks to pass
 88     though to panes underneath it. This will usually cause the pane to show
 89     the modalPane underneath it.
 90 
 91     @type Boolean
 92     @default YES
 93   */
 94   isModal: YES,
 95 
 96   /**
 97     The modal pane to place behind this pane if this pane is modal. This
 98     must be a subclass or an instance of SC.ModalPane.
 99   */
100   modalPane: SC.ModalPane.extend({
101     classNames: 'for-sc-panel'
102   }),
103 
104   // ..........................................................
105   // CONTENT VIEW
106   //
107 
108   /**
109     Set this to the view you want to act as the content within the panel.
110 
111     @type SC.View
112     @default null
113   */
114   contentView: null,
115   contentViewBindingDefault: SC.Binding.single(),
116 
117   /**
118     @param {SC.View} newContent
119   */
120   replaceContent: function(newContent) {
121     this.removeAllChildren() ;
122     if (newContent) this.appendChild(newContent);
123   },
124 
125   /** @private */
126   createChildViews: function() {
127     // if contentView is defined, then create the content
128     var view = this.contentView ;
129     if (view) {
130       view = this.contentView = this.createChildView(view) ;
131       this.childViews = [view] ;
132     }
133   },
134 
135 
136   /**
137     Invoked whenever the content property changes. This method will simply
138     call replaceContent. Override replaceContent to change how the view is
139     swapped out.
140   */
141   contentViewDidChange: function() {
142     this.replaceContent(this.get('contentView'));
143   }.observes('contentView'),
144 
145   // ..........................................................
146   // INTERNAL SUPPORT
147   //
148 
149   /**
150     The name of the theme's `SC.PanelPane` render delegate.
151 
152     @type String
153     @default 'panelRenderDelegate'
154   */
155   renderDelegateName: 'panelRenderDelegate',
156 
157   // get the modal pane.
158   _modalPane: function() {
159     var pane = this.get('modalPane');
160 
161     // instantiate if needed
162     if (pane && pane.isClass) {
163       pane = pane.create({ owner: this });
164       this.set('modalPane', pane);
165     }
166 
167     return pane ;
168   },
169 
170   /** @private - whenever showing on screen, deal with modal pane as well */
171   appendTo: function(elem) {
172     var pane ;
173     if (!this.get('isVisibleInWindow') && this.get('isModal') && (pane = this._modalPane())) {
174       this._isShowingModal = YES;
175       pane.paneWillAppend(this);
176     }
177     return sc_super();
178   },
179 
180   /** @private - when removing from screen, deal with modal pane as well. */
181   remove: function() {
182     var pane, ret = sc_super();
183 
184     if (this._isShowingModal) {
185       this._isShowingModal = NO ;
186       if (pane = this._modalPane()) pane.paneDidRemove(this);
187     }
188     return ret ;
189   },
190 
191   destroy: function() {
192     var modal = this.get('modalPane');
193     if (modal && !modal.isClass) {
194       modal.destroy();
195     }
196 
197     sc_super();
198   },
199 
200   /** @private - if isModal state changes, update pane state if needed. */
201   _isModalDidChange: function() {
202     var modalPane,
203         isModal = this.get('isModal');
204 
205     if (isModal) {
206       if (!this._isShowingModal && (modalPane = this._modalPane())) {
207         this._isShowingModal = YES;
208         modalPane.paneWillAppend(this);
209       }
210     } else {
211       if (this._isShowingModal && (modalPane = this._modalPane())) {
212         this._isShowingModal = NO;
213         modalPane.paneDidRemove(this);
214       }
215     }
216   }.observes('isModal'),
217 
218   /**
219     Called when the pane is shown.  Takes on key pane status.
220   */
221   didShowInDocument: function () {
222    this.becomeKeyPane();
223   },
224 
225   /**
226     Called when the pane is attached.  Takes on key pane status.
227   */
228   didAppendToDocument: function () {
229     this.becomeKeyPane();
230   },
231 
232   /**
233     Called when the pane is detached.  Resigns key pane status.
234   */
235   willRemoveFromDocument: function () {
236     this.resignKeyPane();
237   },
238 
239   /**
240     Called when the pane is about to be hidden.  Resigns key pane status.
241   */
242   willHideInDocument: function () {
243    this.resignKeyPane();
244   },
245 
246   displayProperties: ['ariaLabel', 'ariaLabelledBy', 'ariaDescribedBy']
247 
248 });
249