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 sc_require('system/root_responder');
  8 
  9 
 10 /** @class
 11 
 12   The root object for a SproutCore application. Usually you will create a
 13   single SC.Application instance as your root namespace. SC.Application is
 14   required if you intend to use SC.Responder to route events.
 15 
 16   ## Example
 17 
 18       Contacts = SC.Application.create({
 19         store: SC.Store.create(SC.Record.fixtures),
 20 
 21         // add other useful properties here
 22       });
 23 
 24   @extends SC.ResponderContext
 25   @since SproutCore 1.0
 26 */
 27 SC.Application = SC.Responder.extend(SC.ResponderContext,
 28 /** @scope SC.Application.prototype */ {
 29 
 30   /** @private UNUSED
 31     The current design mode of the application and its views.
 32 
 33     If the application has designModes specified, this property will be set
 34     automatically as the window size changes across the design mode boundaries.
 35 
 36     @property {String}
 37     @default null
 38   */
 39   // designMode: null,
 40 
 41   /**
 42     A hash of the design mode thresholds for this application.
 43 
 44     While a "design" (the manner views are positioned, shaped and styled) may be
 45     flexible enough to stretch up for a large display and to compress down
 46     for a medium sized display, at a certain point it often makes more sense
 47     to stop stretching and compressing and just implement an additional new design
 48     specific to the much different display size. In order to make this possible
 49     and with as much ease as possible, SproutCore includes support for "design
 50     modes". Design modes are based on the current display size and orientation.
 51 
 52     SproutCore supports three size-based design modes by default: 's' for small,
 53     'm' for medium and 'l' for large. Smartphones and handheld devices like the
 54     iPod Touch fall within the small category, tablets and normal desktop displays
 55     fall within the medium category and retina desktops or 4K displays fall
 56     into the large category.
 57 
 58     When the display size crosses a threshold between one size category to
 59     another, SproutCore will update the design mode of each view in the
 60     application, giving you a chance to provide overrides for that specific
 61     size via the special `modeAdjust` property.
 62 
 63     For example, if you wanted to hide a view completely when in the small (s)
 64     mode you could add:
 65 
 66         //...
 67 
 68         mediumPlusView: SC.View.extend({
 69 
 70           // Design mode overrides.
 71           modeAdjust: { s: { isVisible: false } } // Hide the view in 's' or 'small' mode.
 72 
 73         }),
 74 
 75         //...
 76 
 77     As you can see, we simply indicate the property overrides that we want
 78     for the specific mode. To adjust the height for medium mode, you could add:
 79 
 80         //...
 81 
 82         myView: SC.View.extend({
 83 
 84           // The normal layout always applies.
 85           layout: { height: 24 },
 86 
 87           // Design mode overrides.
 88           modeAdjust: { m: { layout: { height: 30 } } // Adjust the height in 'm' or 'medium' mode.
 89 
 90         }),
 91 
 92         //...
 93 
 94     Note that the values in `modeAdjust` are overrides for that mode and the
 95     values will be *reset* to their original values when leaving that mode.
 96 
 97     The second component to design modes is orientation. Each of the size
 98     categories can have two different orientations: 'l' for landscape or 'p' for
 99     portrait. Therefore, you may want to alter the design to account for the
100     device orientation as well using `modeAdjust`. To do this, you simply
101     specify orientation specific designs with the `_l` or `_p` suffix
102     accordingly.
103 
104     For example, you can provide a configuration for a size category with
105     slight deviations for orientations of that size all in just a few lines
106     of code,
107 
108         //...
109 
110         customView: SC.View.extend({
111 
112           // The default alignment for this custom view's contents.
113           alignment: SC.ALIGN_LEFT,
114 
115           // The default line height for this custom view's contents.
116           lineHeight: 40,
117 
118           // Design mode overrides.
119           modeAdjust: {
120             m: { lineHeight: 50 }, // Overrides for medium mode regardless of orientation.
121             m_p: { alignment: SC.ALIGN_CENTER }, // Overrides for medium - portrait mode.
122             m_l: { layout: { top: 20 } } // Overrides for medium - landscape mode.
123           }
124 
125         }),
126 
127         //...
128 
129     ### A note on styling for design modes
130 
131     Class names are automatically applied to each view depending on the mode
132     as found in the SC.DESIGN_MODE_CLASS_NAMES hash. By default, your
133     views will have one of three class names added:
134 
135         > 'sc-small' in small mode
136         > 'sc-medium' in medium mode
137         > 'sc-large' in large mode
138 
139     As well, the `body` element is given an orientation class name that you
140     can use as well:
141 
142         > 'sc-landscape' in landscape orientation
143         > 'sc-portrait' in portrait orientation
144 
145     ### A note on overriding layouts
146 
147     Layout overrides work slightly differently than regular property overrides,
148     because they are set via `adjust`. This means they apply on *top* of the
149     default layout, they don't replace the default layout. For example,
150     the default layout is `{ left: 0, right: 0, top: 0, bottom: 0 }` and if
151     we provide a design mode like,
152 
153         modeAdjust: { l: { layout: { top: 50 } } }
154 
155     The layout becomes `{ left: 0, right: 0, top: 50, bottom: 0 }`. If we had
156     a default layout like `{ centerX: 0, centerY: 0, height: 100, width: 100 }`
157     and we wanted to change it to a left positioned layout, we would need to
158     null out the centerX value like so,
159 
160         modeAdjust: { l: { layout: { centerX: null, left: 0 } } } // Convert to left positioned layout.
161 
162     ### A note on the medium category
163 
164     The medium category covers tablets *and* non-retina desktops and laptops.
165     While we could try to further differentiate between these two categories,
166     there is no safe way to do this and to do so would cause more harm than good.
167     Tablets can be connected to mice and keyboards, desktops can have touch
168     screens and there is no way to know whether a mouse, touch or pointer is
169     going to be used from one event to the next. Therefore the message should
170     be clear, *you should always design for touch*. This means that a medium
171     sized design should be expected to work well on a laptop and a tablet.
172 
173     ### A note on customizing the design mode categories
174 
175     Design mode thresholds are determined by the area of the display divided by
176     the device pixel ratio. In this manner a 1024 x 768 display on a
177     handheld device can be differentiated from a 1024 x 768 display on a
178     desktop. Through testing and research, the three categories of 'small',
179     'medium' and 'large' were chosen with thresholds between them of
180     500,000 sq.px and 2,000,000 sq.px.
181 
182     Therefore, any display area divided by device pixel ratio that is less
183     than 500,000 will be considered 'small' and likewise a calculated area
184     of over 2,000,000 will be considered 'large'. This should be sufficient
185     for almost all device specific designs and as is mentioned earlier,
186     trying to get even more fine-grained is a dangerous endeavor. However,
187     you can set your own thresholds easily enough by overriding this property.
188 
189     @readonly
190     @type Object
191     @default { s: 500000, m: 2000000, l: Infinity }
192   */
193   designModes: {
194     's': 500000, // ex. smart phone display
195     'm': 2000000, // ex. tablet & non-retina desktop display
196     'l': Infinity // ex. retina desktop display and TV
197   },
198 
199   /** @private */
200   init: function () {
201     sc_super();
202 
203     // Initialize the value on the RootResponder when it is ready.
204     SC.ready(this, '_setDesignModes');
205   },
206 
207   /** @private */
208   _setDesignModes: function () {
209     var designModes = this.get('designModes'),
210       responder = SC.RootResponder.responder;
211 
212     if (designModes) {
213       // All we do is pass the value to the root responder for convenience.
214       responder.set('designModes', designModes);
215       // UNUSED.
216       // this.bind('designMode', SC.Binding.from('SC.RootResponder.responder.currentDesignMode'));
217     }
218   }
219 
220 });
221