lettuce
Version:
Lettuce JS, Mini Mobile Framework for Romantic with DSL.
701 lines (630 loc) • 23.8 kB
JavaScript
/*
* MelonJS Game Engine
* Copyright (C) 2011 - 2013 melonJS
* http://www.melonjs.org
*
*/
(function () {
/**
* A singleton object representing the device capabilities and specific events
* @namespace me.device
* @memberOf me
*/
me.device = (function () {
// defines object for holding public information/functionality.
var api = {};
// private properties
var accelInitialized = false;
var deviceOrientationInitialized = false;
var devicePixelRatio = null;
/**
* check the device capapbilities
* @ignore
*/
api._check = function () {
// detect device type/platform
me.device._detectDevice();
// future proofing (MS) feature detection
me.device.pointerEnabled = me.agent.prefixed("pointerEnabled", navigator);
navigator.maxTouchPoints = me.agent.prefixed("maxTouchPoints", navigator) || 0;
window.gesture = me.agent.prefixed("gesture");
// detect touch capabilities
me.device.touch = ("createTouch" in document) || ("ontouchstart" in window) ||
(navigator.isCocoonJS) || (me.device.pointerEnabled && (navigator.maxTouchPoints > 0));
// accelerometer detection
me.device.hasAccelerometer = (
(typeof (window.DeviceMotionEvent) !== "undefined") || (
(typeof (window.Windows) !== "undefined") &&
(typeof (Windows.Devices.Sensors.Accelerometer) === "function")
)
);
// pointerlock detection
this.hasPointerLockSupport = me.agent.prefixed("pointerLockElement", document);
if (this.hasPointerLockSupport) {
document.exitPointerLock = me.agent.prefixed("exitPointerLock", document);
}
// device motion detection
if (window.DeviceOrientationEvent) {
me.device.hasDeviceOrientation = true;
}
// fullscreen api detection & polyfill when possible
this.hasFullscreenSupport = me.agent.prefixed("fullscreenEnabled", document) ||
document.mozFullScreenEnabled;
document.exitFullscreen = me.agent.prefixed("cancelFullScreen", document) ||
me.agent.prefixed("exitFullscreen", document);
// vibration API poyfill
navigator.vibrate = me.agent.prefixed("vibrate", navigator);
try {
api.localStorage = !!window.localStorage;
} catch (e) {
// the above generates an exception when cookies are blocked
api.localStorage = false;
}
// set pause/stop action on losing focus
window.addEventListener("blur", function () {
if (me.sys.stopOnBlur) {
me.state.stop(true);
}
if (me.sys.pauseOnBlur) {
me.state.pause(true);
}
}, false);
// set restart/resume action on gaining focus
window.addEventListener("focus", function () {
if (me.sys.stopOnBlur) {
me.state.restart(true);
}
if (me.sys.resumeOnFocus) {
me.state.resume(true);
}
}, false);
// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") {
// Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
// register on the event if supported
if (typeof (visibilityChange) === "string") {
// add the corresponding event listener
document.addEventListener(visibilityChange,
function () {
if (document[hidden]) {
if (me.sys.stopOnBlur) {
me.state.stop(true);
}
if (me.sys.pauseOnBlur) {
me.state.pause(true);
}
} else {
if (me.sys.stopOnBlur) {
me.state.restart(true);
}
if (me.sys.resumeOnFocus) {
me.state.resume(true);
}
}
}, false
);
}
};
/**
* detect the device type
* @ignore
*/
api._detectDevice = function () {
// iOS Device ?
me.device.iOS = me.device.ua.match(/iPhone|iPad|iPod/i) || false;
// Android Device ?
me.device.android = me.device.ua.match(/Android/i) || false;
me.device.android2 = me.device.ua.match(/Android 2/i) || false;
// Windows Device ?
me.device.wp = me.device.ua.match(/Windows Phone/i) || false;
// Kindle device ?
me.device.BlackBerry = me.device.ua.match(/BlackBerry/i) || false;
// Kindle device ?
me.device.Kindle = me.device.ua.match(/Kindle|Silk.*Mobile Safari/i) || false;
// Mobile platform
me.device.isMobile = me.device.ua.match(/Mobi/i) ||
me.device.iOS ||
me.device.android ||
me.device.wp ||
me.device.BlackBerry ||
me.device.Kindle ||
me.device.iOS || false;
};
/*
* PUBLIC Properties & Functions
*/
// Browser capabilities
/**
* Browser User Agent
* @type Boolean
* @readonly
* @name ua
* @memberOf me.device
*/
api.ua = navigator.userAgent;
/**
* Browser Local Storage capabilities <br>
* (this flag will be set to false if cookies are blocked)
* @type Boolean
* @readonly
* @name localStorage
* @memberOf me.device
*/
api.localStorage = false;
/**
* Browser accelerometer capabilities
* @type Boolean
* @readonly
* @name hasAccelerometer
* @memberOf me.device
*/
api.hasAccelerometer = false;
/**
* Browser device orientation
* @type Boolean
* @readonly
* @name hasDeviceOrientation
* @memberOf me.device
*/
api.hasDeviceOrientation = false;
/**
* Browser full screen support
* @type Boolean
* @readonly
* @name hasFullscreenSupport
* @memberOf me.device
*/
api.hasFullscreenSupport = false;
/**
* Browser pointerlock api support
* @type Boolean
* @readonly
* @name hasPointerLockSupport
* @memberOf me.device
*/
api.hasPointerLockSupport = false;
/**
* Browser Base64 decoding capability
* @type Boolean
* @readonly
* @name nativeBase64
* @memberOf me.device
*/
api.nativeBase64 = (typeof(window.atob) === "function");
/**
* Touch capabilities
* @type Boolean
* @readonly
* @name touch
* @memberOf me.device
*/
api.touch = false;
/**
* equals to true if a mobile device <br>
* (Android | iPhone | iPad | iPod | BlackBerry | Windows Phone | Kindle)
* @type Boolean
* @readonly
* @name isMobile
* @memberOf me.device
*/
api.isMobile = false;
/**
* equals to true if the device is an iOS platform <br>
* @type Boolean
* @readonly
* @name iOS
* @memberOf me.device
*/
api.iOS = false;
/**
* equals to true if the device is an Android platform <br>
* @type Boolean
* @readonly
* @name android
* @memberOf me.device
*/
api.android = false;
/**
* equals to true if the device is an Android 2.x platform <br>
* @type Boolean
* @readonly
* @name android2
* @memberOf me.device
*/
api.android2 = false;
/**
* equals to true if the device is a Windows Phone platform <br>
* @type Boolean
* @readonly
* @name wp
* @memberOf me.device
*/
api.wp = false;
/**
* equals to true if the device is a BlackBerry platform <br>
* @type Boolean
* @readonly
* @name BlackBerry
* @memberOf me.device
*/
api.BlackBerry = false;
/**
* equals to true if the device is a Kindle platform <br>
* @type Boolean
* @readonly
* @name Kindle
* @memberOf me.device
*/
api.Kindle = false;
/**
* The device current orientation status. <br>
* 0 : default orientation<br>
* 90 : 90 degrees clockwise from default<br>
* -90 : 90 degrees anti-clockwise from default<br>
* 180 : 180 degrees from default
* @type Number
* @readonly
* @name orientation
* @memberOf me.device
*/
api.orientation = 0;
/**
* contains the g-force acceleration along the x-axis.
* @public
* @type Number
* @readonly
* @name accelerationX
* @memberOf me.device
*/
api.accelerationX = 0;
/**
* contains the g-force acceleration along the y-axis.
* @public
* @type Number
* @readonly
* @name accelerationY
* @memberOf me.device
*/
api.accelerationY = 0;
/**
* contains the g-force acceleration along the z-axis.
* @public
* @type Number
* @readonly
* @name accelerationZ
* @memberOf me.device
*/
api.accelerationZ = 0;
/**
* Device orientation Gamma property. Gives angle on tilting a portrait held phone left or right
* @public
* @type Number
* @readonly
* @name gamma
* @memberOf me.device
*/
api.gamma = 0;
/**
* Device orientation Beta property. Gives angle on tilting a portrait held phone forward or backward
* @public
* @type Number
* @readonly
* @name beta
* @memberOf me.device
*/
api.beta = 0;
/**
* Device orientation Alpha property. Gives angle based on the rotation of the phone around its z axis.
* The z-axis is perpendicular to the phone, facing out from the center of the screen.
* @public
* @type Number
* @readonly
* @name alpha
* @memberOf me.device
*/
api.alpha = 0;
/**
* Triggers a fullscreen request. Requires fullscreen support from the browser/device.
* @name requestFullscreen
* @memberOf me.device
* @function
* @param {Object} [element=default canvas object] the element to be set in full-screen mode.
* @example
* // add a keyboard shortcut to toggle Fullscreen mode on/off
* me.input.bindKey(me.input.KEY.F, "toggleFullscreen");
* me.event.subscribe(me.event.KEYDOWN, function (action, keyCode, edge) {
* // toggle fullscreen on/off
* if (action === "toggleFullscreen") {
* if (!me.device.isFullscreen) {
* me.device.requestFullscreen();
* } else {
* me.device.exitFullscreen();
* }
* }
* });
*/
api.requestFullscreen = function (element) {
if (this.hasFullscreenSupport) {
element = element || me.video.getWrapper();
element.requestFullscreen = me.agent.prefixed("requestFullscreen", element) ||
element.mozRequestFullScreen;
element.requestFullscreen();
}
};
/**
* Exit fullscreen mode. Requires fullscreen support from the browser/device.
* @name exitFullscreen
* @memberOf me.device
* @function
*/
api.exitFullscreen = function () {
if (this.hasFullscreenSupport) {
document.exitFullscreen();
}
};
/**
* return the device pixel ratio
* @name getPixelRatio
* @memberOf me.device
* @function
*/
api.getPixelRatio = function () {
if (devicePixelRatio === null) {
var _context;
if (typeof me.video.renderer !== "undefined") {
_context = me.video.renderer.getScreenContext();
} else {
_context = me.Renderer.prototype.getContext2d(document.createElement("canvas"));
}
var _devicePixelRatio = window.devicePixelRatio || 1,
_backingStoreRatio = me.agent.prefixed("backingStorePixelRatio", _context) || 1;
devicePixelRatio = _devicePixelRatio / _backingStoreRatio;
}
return devicePixelRatio;
};
/**
* return the device storage
* @name getStorage
* @memberOf me.device
* @function
* @param {String} [type="local"]
* @return me.save object
*/
api.getStorage = function (type) {
type = type || "local";
switch (type) {
case "local" :
return me.save;
default :
throw new me.Error("storage type " + type + " not supported");
}
};
/**
* event management (Accelerometer)
* http://www.mobilexweb.com/samples/ball.html
* http://www.mobilexweb.com/blog/safari-ios-accelerometer-websockets-html5
* @ignore
*/
function onDeviceMotion(e) {
if (e.reading) {
// For Windows 8 devices
api.accelerationX = e.reading.accelerationX;
api.accelerationY = e.reading.accelerationY;
api.accelerationZ = e.reading.accelerationZ;
}
else {
// Accelerometer information
api.accelerationX = e.accelerationIncludingGravity.x;
api.accelerationY = e.accelerationIncludingGravity.y;
api.accelerationZ = e.accelerationIncludingGravity.z;
}
}
function onDeviceRotate(e) {
api.gamma = e.gamma;
api.beta = e.beta;
api.alpha = e.alpha;
}
/**
* Enters pointer lock, requesting it from the user first. Works on supported devices & browsers
* Must be called in a click event or an event that requires user interaction.
* If you need to run handle events for errors or change of the pointer lock, see below.
* @name turnOnPointerLock
* @memberOf me.device
* @function
* @example
* document.addEventListener("pointerlockchange", pointerlockchange, false);
* document.addEventListener("mozpointerlockchange", pointerlockchange, false);
* document.addEventListener("webkitpointerlockchange", pointerlockchange, false);
*
* document.addEventListener("pointerlockerror", pointerlockerror, false);
* document.addEventListener("mozpointerlockerror", pointerlockerror, false);
* document.addEventListener("webkitpointerlockerror", pointerlockerror, false);
*/
api.turnOnPointerLock = function () {
if (this.hasPointerLockSupport) {
var element = me.video.getWrapper();
if (me.device.ua.match(/Firefox/i)) {
var fullscreenchange = function () {
if ((me.agent.prefixed("fullscreenElement", document) ||
document.mozFullScreenElement) === element) {
document.removeEventListener("fullscreenchange", fullscreenchange);
document.removeEventListener("mozfullscreenchange", fullscreenchange);
element.requestPointerLock = me.agent.prefixed("requestPointerLock", element);
element.requestPointerLock();
}
};
document.addEventListener("fullscreenchange", fullscreenchange, false);
document.addEventListener("mozfullscreenchange", fullscreenchange, false);
me.device.requestFullscreen();
}
else {
element.requestPointerLock();
}
}
};
/**
* Exits pointer lock. Works on supported devices & browsers
* @name turnOffPointerLock
* @memberOf me.device
* @function
*/
api.turnOffPointerLock = function () {
if (this.hasPointerLockSupport) {
document.exitPointerLock();
}
};
/**
* watch Accelerator event
* @name watchAccelerometer
* @memberOf me.device
* @public
* @function
* @return {Boolean} false if not supported by the device
*/
api.watchAccelerometer = function () {
if (me.device.hasAccelerometer) {
if (!accelInitialized) {
if (typeof Windows === "undefined") {
// add a listener for the devicemotion event
window.addEventListener("devicemotion", onDeviceMotion, false);
}
else {
// On Windows 8 Device
var accelerometer = Windows.Devices.Sensors.Accelerometer.getDefault();
if (accelerometer) {
// Capture event at regular intervals
var minInterval = accelerometer.minimumReportInterval;
var Interval = minInterval >= 16 ? minInterval : 25;
accelerometer.reportInterval = Interval;
accelerometer.addEventListener("readingchanged", onDeviceMotion, false);
}
}
accelInitialized = true;
}
return true;
}
return false;
};
/**
* unwatch Accelerometor event
* @name unwatchAccelerometer
* @memberOf me.device
* @public
* @function
*/
api.unwatchAccelerometer = function () {
if (accelInitialized) {
if (typeof Windows === "undefined") {
// add a listener for the mouse
window.removeEventListener("devicemotion", onDeviceMotion, false);
} else {
// On Windows 8 Devices
var accelerometer = Windows.Device.Sensors.Accelerometer.getDefault();
accelerometer.removeEventListener("readingchanged", onDeviceMotion, false);
}
accelInitialized = false;
}
};
/**
* watch the device orientation event
* @name watchDeviceOrientation
* @memberOf me.device
* @public
* @function
* @return {Boolean} false if not supported by the device
*/
api.watchDeviceOrientation = function () {
if (me.device.hasDeviceOrientation && !deviceOrientationInitialized) {
window.addEventListener("deviceorientation", onDeviceRotate, false);
deviceOrientationInitialized = true;
}
return false;
};
/**
* unwatch Device orientation event
* @name unwatchDeviceOrientation
* @memberOf me.device
* @public
* @function
*/
api.unwatchDeviceOrientation = function () {
if (deviceOrientationInitialized) {
window.removeEventListener("deviceorientation", onDeviceRotate, false);
deviceOrientationInitialized = false;
}
};
/**
* the vibrate method pulses the vibration hardware on the device, <br>
* If the device doesn't support vibration, this method has no effect. <br>
* If a vibration pattern is already in progress when this method is called,
* the previous pattern is halted and the new one begins instead.
* @name vibrate
* @memberOf me.device
* @public
* @function
* @param {Number|Number[]} pattern pattern of vibration and pause intervals
* @example
* // vibrate for 1000 ms
* navigator.vibrate(1000);
* // or alternatively
* navigator.vibrate([1000]);
* vibrate for 50 ms, be still for 100 ms, and then vibrate for 150 ms:
* navigator.vibrate([50, 100, 150]);
* // cancel any existing vibrations
* navigator.vibrate(0);
*/
api.vibrate = function (pattern) {
if (navigator.vibrate) {
navigator.vibrate(pattern);
}
};
return api;
})();
/**
* Returns true if the browser/device is in full screen mode.
* @name isFullscreen
* @memberOf me.device
* @public
* @type Boolean
* @readonly
* @return {boolean}
*/
Object.defineProperty(me.device, "isFullscreen", {
get: function () {
if (me.device.hasFullscreenSupport) {
var el = me.agent.prefixed("fullscreenElement", document) ||
document.mozFullScreenElement;
return (el === me.video.getWrapper());
} else {
return false;
}
}
});
/**
* Returns true if the browser/device has audio capabilities.
* @name sound
* @memberOf me.device
* @public
* @type Boolean
* @readonly
* @return {boolean}
*/
Object.defineProperty(me.device, "sound", {
get: function () {
return !Howler.noAudio;
}
});
})();