UNPKG

lettuce

Version:

Lettuce JS, Mini Mobile Framework for Romantic with DSL.

701 lines (630 loc) 23.8 kB
/* * 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; } }); })();