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