// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // Portions ©2008-2011 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ==========================================================================

sc_require('system/core_query'); sc_require('system/ready'); sc_require('system/root_responder'); sc_require('system/platform');

SC.PORTRAIT_ORIENTATION = 'portrait'; SC.LANDSCAPE_ORIENTATION = 'landscape'; SC.NO_ORIENTATION = 'desktop'; // value 'desktop' for backwards compatibility

/**

The device object allows you to check device specific properties such as
orientation and if the device is offline, as well as observe when they change
state.

## Orientation
When a touch device changes orientation, the orientation property will be
set accordingly which you can observe

## Offline support
In order to build a good offline-capable web application, you need to know
when your app has gone offline so you can for instance queue your server
requests for a later time or provide a specific UI/message.

Similarly, you also need to know when your application has returned to an
'online' state again, so that you can re-synchronize with the server or do
anything else that might be needed.

By observing the 'isOffline' property you can be notified when this state
changes. Note that this property is only connected to the navigator.onLine
property, which is available on most modern browsers.

*/ SC.device = SC.Object.create({

/**
  Sets the orientation for devices, either SC.LANDSCAPE_ORIENTATION
  or SC.PORTRAIT_ORIENTATION.

  @type String
  @default SC.PORTRAIT_ORIENTATION
*/
orientation: SC.PORTRAIT_ORIENTATION,

/**
  Indicates whether the device is currently online or offline. For browsers
  that do not support this feature, the default value is NO.

  Is currently inverse of the navigator.onLine property. Most modern browsers
  will update this property when switching to or from the browser's Offline
  mode, and when losing/regaining network connectivity.

  @type Boolean
  @default NO
*/
isOffline: NO,

/**
  Returns a Point containing the last known X and Y coordinates of the
  mouse, if present.

  @type Point
*/
mouseLocation: function() {
  var responder = SC.RootResponder.responder,
      lastX = responder._lastMoveX,
      lastY = responder._lastMoveY;

  if (SC.empty(lastX) || SC.empty(lastY)) {
    return null;
  }

  return { x: lastX, y: lastY };
}.property(),

/**
  Initialize the object with some properties up front
*/
init: function() {
  sc_super();

  if (navigator && navigator.onLine === false) {
    this.set('isOffline', YES);
  }
},

/**
  As soon as the DOM is up and running, make sure we attach necessary
  event handlers
*/
setup: function() {
  var responder = SC.RootResponder.responder;
  responder.listenFor(['online', 'offline'], window, this);

  this.orientationHandlingShouldChange();
},

// ..........................................................
// ORIENTATION HANDLING
//

/**
  Determines which method to use for orientation changes.
  Either detects orientation changes via the current size
  of the window, or by the window.onorientationchange event.
*/
orientationHandlingShouldChange: function() {
  if (SC.platform.windowSizeDeterminesOrientation) {
    SC.Event.remove(window, 'orientationchange', this, this.orientationchange);
    this.windowSizeDidChange(SC.RootResponder.responder.get('currentWindowSize'));
  } else if (SC.platform.supportsOrientationChange) {
    SC.Event.add(window, 'orientationchange', this, this.orientationchange);
    this.orientationchange();
  }
},

/**
  @param {Hash} newSize The new size of the window
  @returns YES if the method altered the orientation, NO otherwise
*/
windowSizeDidChange: function(newSize) {
  if (SC.platform.windowSizeDeterminesOrientation) {
    if (newSize.height >= newSize.width) {
      SC.device.set('orientation', SC.PORTRAIT_ORIENTATION);
    } else {
      SC.device.set('orientation', SC.LANDSCAPE_ORIENTATION);
    }

    return YES;
  }
  return NO;
},

/**
  Called when the window.onorientationchange event is fired.
*/
orientationchange: function(evt) {
  SC.run(function() {
    if (window.orientation === 0 || window.orientation === 180) {
      SC.device.set('orientation', SC.PORTRAIT_ORIENTATION);
    } else {
      SC.device.set('orientation', SC.LANDSCAPE_ORIENTATION);
    }
  });
},

/** @private */
orientationObserver: function () {
  var body = SC.$(document.body),
      orientation = this.get('orientation');

  if (orientation === SC.PORTRAIT_ORIENTATION) {
    body.addClass('sc-portrait');
  } else {
    body.removeClass('sc-portrait');
  }

  if (orientation === SC.LANDSCAPE_ORIENTATION) {
    body.addClass('sc-landscape');
  } else {
    body.removeClass('sc-landscape');
  }
}.observes('orientation'),

// ..........................................................
// CONNECTION HANDLING
//

online: function(evt) {
  SC.run(function () {
    this.set('isOffline', NO);
  }, this);
},

offline: function(evt) {
  SC.run(function () {
    this.set('isOffline', YES);
  }, this);
}

});

/*

Invoked when the document is ready, but before main is called.  Creates
an instance and sets up event listeners as needed.

*/ SC.ready(function() {

SC.device.setup();

});