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('system/core_query'); 9 sc_require('system/ready'); 10 sc_require('system/root_responder'); 11 sc_require('system/platform'); 12 13 SC.PORTRAIT_ORIENTATION = 'portrait'; 14 SC.LANDSCAPE_ORIENTATION = 'landscape'; 15 SC.NO_ORIENTATION = 'desktop'; // value 'desktop' for backwards compatibility 16 17 /** 18 The device object allows you to check device specific properties such as 19 orientation and if the device is offline, as well as observe when they change 20 state. 21 22 ## Orientation 23 When a touch device changes orientation, the orientation property will be 24 set accordingly which you can observe 25 26 ## Offline support 27 In order to build a good offline-capable web application, you need to know 28 when your app has gone offline so you can for instance queue your server 29 requests for a later time or provide a specific UI/message. 30 31 Similarly, you also need to know when your application has returned to an 32 'online' state again, so that you can re-synchronize with the server or do 33 anything else that might be needed. 34 35 By observing the 'isOffline' property you can be notified when this state 36 changes. Note that this property is only connected to the navigator.onLine 37 property, which is available on most modern browsers. 38 39 */ 40 SC.device = SC.Object.create({ 41 42 /** 43 Sets the orientation for devices, either SC.LANDSCAPE_ORIENTATION 44 or SC.PORTRAIT_ORIENTATION. 45 46 @type String 47 @default SC.PORTRAIT_ORIENTATION 48 */ 49 orientation: SC.PORTRAIT_ORIENTATION, 50 51 /** 52 Indicates whether the device is currently online or offline. For browsers 53 that do not support this feature, the default value is NO. 54 55 Is currently inverse of the navigator.onLine property. Most modern browsers 56 will update this property when switching to or from the browser's Offline 57 mode, and when losing/regaining network connectivity. 58 59 @type Boolean 60 @default NO 61 */ 62 isOffline: NO, 63 64 /** 65 Returns a Point containing the last known X and Y coordinates of the 66 mouse, if present. 67 68 @type Point 69 */ 70 mouseLocation: function() { 71 var responder = SC.RootResponder.responder, 72 lastX = responder._lastMoveX, 73 lastY = responder._lastMoveY; 74 75 if (SC.empty(lastX) || SC.empty(lastY)) { 76 return null; 77 } 78 79 return { x: lastX, y: lastY }; 80 }.property(), 81 82 /** 83 Initialize the object with some properties up front 84 */ 85 init: function() { 86 sc_super(); 87 88 if (navigator && navigator.onLine === false) { 89 this.set('isOffline', YES); 90 } 91 }, 92 93 /** 94 As soon as the DOM is up and running, make sure we attach necessary 95 event handlers 96 */ 97 setup: function() { 98 var responder = SC.RootResponder.responder; 99 responder.listenFor(['online', 'offline'], window, this); 100 101 this.orientationHandlingShouldChange(); 102 }, 103 104 // .......................................................... 105 // ORIENTATION HANDLING 106 // 107 108 /** 109 Determines which method to use for orientation changes. 110 Either detects orientation changes via the current size 111 of the window, or by the window.onorientationchange event. 112 */ 113 orientationHandlingShouldChange: function() { 114 if (SC.platform.windowSizeDeterminesOrientation) { 115 SC.Event.remove(window, 'orientationchange', this, this.orientationchange); 116 this.windowSizeDidChange(SC.RootResponder.responder.get('currentWindowSize')); 117 } else if (SC.platform.supportsOrientationChange) { 118 SC.Event.add(window, 'orientationchange', this, this.orientationchange); 119 this.orientationchange(); 120 } 121 }, 122 123 /** 124 @param {Hash} newSize The new size of the window 125 @returns YES if the method altered the orientation, NO otherwise 126 */ 127 windowSizeDidChange: function(newSize) { 128 if (SC.platform.windowSizeDeterminesOrientation) { 129 if (newSize.height >= newSize.width) { 130 SC.device.set('orientation', SC.PORTRAIT_ORIENTATION); 131 } else { 132 SC.device.set('orientation', SC.LANDSCAPE_ORIENTATION); 133 } 134 135 return YES; 136 } 137 return NO; 138 }, 139 140 /** 141 Called when the window.onorientationchange event is fired. 142 */ 143 orientationchange: function(evt) { 144 SC.run(function() { 145 if (window.orientation === 0 || window.orientation === 180) { 146 SC.device.set('orientation', SC.PORTRAIT_ORIENTATION); 147 } else { 148 SC.device.set('orientation', SC.LANDSCAPE_ORIENTATION); 149 } 150 }); 151 }, 152 153 /** @private */ 154 orientationObserver: function () { 155 var body = SC.$(document.body), 156 orientation = this.get('orientation'); 157 158 if (orientation === SC.PORTRAIT_ORIENTATION) { 159 body.addClass('sc-portrait'); 160 } else { 161 body.removeClass('sc-portrait'); 162 } 163 164 if (orientation === SC.LANDSCAPE_ORIENTATION) { 165 body.addClass('sc-landscape'); 166 } else { 167 body.removeClass('sc-landscape'); 168 } 169 }.observes('orientation'), 170 171 172 // .......................................................... 173 // CONNECTION HANDLING 174 // 175 176 online: function(evt) { 177 SC.run(function () { 178 this.set('isOffline', NO); 179 }, this); 180 }, 181 182 offline: function(evt) { 183 SC.run(function () { 184 this.set('isOffline', YES); 185 }, this); 186 } 187 188 }); 189 190 /* 191 Invoked when the document is ready, but before main is called. Creates 192 an instance and sets up event listeners as needed. 193 */ 194 SC.ready(function() { 195 SC.device.setup(); 196 }); 197