melonjs 10.12.0 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +6 -6
  3. package/dist/melonjs.js +22651 -22529
  4. package/dist/melonjs.min.js +5 -6
  5. package/dist/melonjs.module.d.ts +195 -195
  6. package/dist/melonjs.module.js +22107 -21977
  7. package/package.json +14 -14
  8. package/src/application/application.js +231 -0
  9. package/src/audio/audio.js +13 -7
  10. package/src/camera/camera2d.js +6 -6
  11. package/src/game.js +9 -232
  12. package/src/index.js +3 -3
  13. package/src/input/keyboard.js +2 -2
  14. package/src/input/pointer.js +4 -5
  15. package/src/input/pointerevent.js +8 -8
  16. package/src/lang/deprecated.js +0 -29
  17. package/src/level/level.js +2 -2
  18. package/src/level/tiled/TMXLayer.js +2 -2
  19. package/src/level/tiled/TMXTileMap.js +3 -3
  20. package/src/loader/loader.js +64 -28
  21. package/src/loader/loadingscreen.js +28 -115
  22. package/src/loader/melonjs_logo.png +0 -0
  23. package/src/physics/body.js +27 -51
  24. package/src/physics/detector.js +3 -3
  25. package/src/physics/quadtree.js +58 -29
  26. package/src/physics/world.js +32 -3
  27. package/src/polyfill/index.js +4 -0
  28. package/src/renderable/container.js +2 -2
  29. package/src/renderable/imagelayer.js +8 -8
  30. package/src/renderable/light2d.js +40 -11
  31. package/src/renderable/trigger.js +4 -4
  32. package/src/state/stage.js +1 -1
  33. package/src/state/state.js +50 -3
  34. package/src/system/device.js +808 -1039
  35. package/src/system/dom.js +69 -0
  36. package/src/system/event.js +13 -1
  37. package/src/system/platform.js +32 -0
  38. package/src/system/save.js +23 -14
  39. package/src/system/timer.js +12 -35
  40. package/src/text/bitmaptext.js +1 -2
  41. package/src/text/text.js +10 -14
  42. package/src/text/textmetrics.js +1 -2
  43. package/src/tweens/tween.js +6 -6
  44. package/src/utils/string.js +13 -24
  45. package/src/video/canvas/canvas_renderer.js +3 -2
  46. package/src/video/renderer.js +2 -2
  47. package/src/video/texture/canvas_texture.js +36 -2
  48. package/src/video/video.js +15 -9
  49. package/src/video/webgl/glshader.js +1 -1
  50. package/src/video/webgl/webgl_renderer.js +1 -1
@@ -1,21 +1,22 @@
1
- import { hasAudio } from "./../audio/audio.js";
2
1
  import { getParent } from "./../video/video.js";
3
2
  import save from "./save.js";
4
3
  import { prefixed } from "./../utils/agent.js";
5
- import state from "./../state/state.js";
6
- import * as event from "./event.js";
4
+ import { DOMContentLoaded } from "./dom.js";
5
+ import * as device_platform from "./platform.js"; // export * as name1 from …; // ECMAScript® 2020
6
+
7
+ /**
8
+ * device type and capabilities
9
+ * @namespace device
10
+ */
7
11
 
8
- // private properties
9
12
  let accelInitialized = false;
10
13
  let deviceOrientationInitialized = false;
11
-
12
14
  // swipe utility fn & flag
13
15
  let swipeEnabled = true;
16
+ // a cache DOMRect object
17
+ let domRect = {left: 0, top: 0, x: 0, y: 0, width: 0, height: 0, right: 0, bottom: 0};
14
18
 
15
- /**
16
- * @ignore
17
- */
18
- function _disableSwipeFn(e) {
19
+ function disableSwipeFn(e) {
19
20
  e.preventDefault();
20
21
  if (typeof globalThis.scroll === "function") {
21
22
  globalThis.scroll(0, 0);
@@ -23,1109 +24,877 @@ function _disableSwipeFn(e) {
23
24
  return false;
24
25
  };
25
26
 
26
- // DOM loading stuff
27
- let readyBound = false, isReady = false, readyList = [];
27
+ function hasLocalStorage() {
28
+ try {
29
+ return !!globalThis.localStorage;
30
+ } catch (e) {
31
+ // the above generates an exception when cookies are blocked
32
+ return false;
33
+ }
34
+ }
35
+
36
+ function hasOffscreenCanvas() {
37
+ try {
38
+ // some browser (e.g. Safari) implements WebGL1 and WebGL2 contexts only
39
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=801176
40
+ return (typeof globalThis.OffscreenCanvas !== "undefined") && ((new globalThis.OffscreenCanvas(0, 0).getContext( "2d" )) !== null);
41
+ } catch (e) {
42
+ return false;
43
+ }
44
+ }
28
45
 
29
46
  /**
30
- * // called to check if the device is ready
31
- * @ignore
47
+ * used by [un]watchAccelerometer()
32
48
  */
33
- function _domReady() {
34
- // Make sure that the DOM is not already loaded
35
- if (!isReady) {
36
- // be sure document.body is there
37
- if (typeof globalThis.document !== "undefined" && !globalThis.document.body) {
38
- return setTimeout(_domReady, 13);
39
- }
49
+ function onDeviceMotion(e) {
50
+ // Accelerometer information
51
+ accelerationX = e.accelerationIncludingGravity.x;
52
+ accelerationY = e.accelerationIncludingGravity.y;
53
+ accelerationZ = e.accelerationIncludingGravity.z;
54
+ };
40
55
 
41
- // clean up loading event
42
- if (typeof globalThis.document !== "undefined" && typeof globalThis.document.removeEventListener === "function") {
43
- globalThis.document.removeEventListener(
44
- "DOMContentLoaded",
45
- this._domReady,
46
- false
47
- );
48
- }
56
+ /**
57
+ * used by [un]watchDeviceOrientation()
58
+ */
59
+ export function onDeviceRotate(e) {
60
+ gamma = e.gamma;
61
+ beta = e.beta;
62
+ alpha = e.alpha;
63
+ };
49
64
 
50
- if (typeof globalThis.removeEventListener === "function") {
51
- // remove the event on globalThis.onload (always added in `onReady`)
52
- globalThis.removeEventListener("load", _domReady, false);
53
- }
65
+ /**
66
+ * the device platform type
67
+ * @name platform
68
+ * @memberof device
69
+ * @readonly
70
+ * @public
71
+ * @type {device.platform}
72
+ */
73
+ export let platform = device_platform;
54
74
 
55
- // execute all callbacks
56
- while (readyList.length) {
57
- readyList.shift().call(globalThis, []);
58
- }
75
+ /**
76
+ * True if the browser supports Touch Events
77
+ * @name touchEvent
78
+ * @memberof device
79
+ * @type {boolean}
80
+ * @readonly
81
+ * @public
82
+ */
83
+ export const touchEvent = !!("ontouchstart" in globalThis);
59
84
 
60
- // Remember that the DOM is ready
61
- isReady = true;
62
- }
63
- };
85
+ /**
86
+ * True if the browser supports Pointer Events
87
+ * @name pointerEvent
88
+ * @memberof device
89
+ * @type {boolean}
90
+ * @readonly
91
+ * @public
92
+ */
93
+ export const pointerEvent = !!globalThis.PointerEvent;
64
94
 
65
- // a cache DOMRect object
66
- let _domRect = {left: 0, top: 0, x: 0, y: 0, width: 0, height: 0, right: 0, bottom: 0};
95
+ /**
96
+ * Touch capabilities (support either Touch or Pointer events)
97
+ * @name touch
98
+ * @memberof device
99
+ * @type {boolean}
100
+ * @readonly
101
+ * @public
102
+ */
103
+ export const touch = touchEvent || pointerEvent;
67
104
 
68
105
  /**
69
- * detect the device type
70
- * @ignore
106
+ * the maximum number of simultaneous touch contact points are supported by the current device.
107
+ * @name maxTouchPoints
108
+ * @memberof device
109
+ * @type {number}
110
+ * @readonly
111
+ * @public
112
+ * @example
113
+ * if (me.device.maxTouchPoints > 1) {
114
+ * // device supports multi-touch
115
+ * }
71
116
  */
72
- function _detectDevice() {
73
- // iOS Device ?
74
- device.iOS = /iPhone|iPad|iPod/i.test(device.ua);
75
- // Android Device ?
76
- device.android = /Android/i.test(device.ua);
77
- device.android2 = /Android 2/i.test(device.ua);
78
- // Linux platform
79
- device.linux = /Linux/i.test(device.ua);
80
- // Chrome OS ?
81
- device.chromeOS = /CrOS/.test(device.ua);
82
- // Windows Device ?
83
- device.wp = /Windows Phone/i.test(device.ua);
84
- // Blackberry device ?
85
- device.BlackBerry = /BlackBerry/i.test(device.ua);
86
- // Kindle device ?
87
- device.Kindle = /Kindle|Silk.*Mobile Safari/i.test(device.ua);
88
- // Mobile platform
89
- device.isMobile = /Mobi/i.test(device.ua) ||
90
- device.iOS ||
91
- device.android ||
92
- device.wp ||
93
- device.BlackBerry ||
94
- device.Kindle || false;
95
- // ejecta
96
- device.ejecta = (typeof globalThis.ejecta !== "undefined");
97
- // Wechat
98
- device.isWeixin = /MicroMessenger/i.test(device.ua);
99
- };
117
+ export const maxTouchPoints = touch ? (pointerEvent ? globalThis.navigator.maxTouchPoints || 1 : 10) : 1;
100
118
 
101
119
  /**
102
- * check the device capapbilities
103
- * @ignore
120
+ * W3C standard wheel events
121
+ * @name wheel
122
+ * @memberof device
123
+ * @type {boolean}
124
+ * @readonly
125
+ * @public
104
126
  */
105
- function _checkCapabilities() {
127
+ export const wheel = typeof globalThis.document !== "undefined" && "onwheel" in globalThis.document.createElement("div");
106
128
 
107
- // detect device type/platform
108
- _detectDevice();
109
129
 
110
- // Touch/Gesture Event feature detection
111
- device.TouchEvent = !!("ontouchstart" in globalThis);
112
- device.PointerEvent = !!globalThis.PointerEvent;
113
- globalThis.gesture = prefixed("gesture");
130
+ /**
131
+ * Browser pointerlock api support
132
+ * @name hasPointerLockSupport
133
+ * @memberof device
134
+ * @type {boolean}
135
+ * @readonly
136
+ * @public
137
+ */
138
+ export const hasPointerLockSupport = typeof globalThis.document !== "undefined" && typeof globalThis.document.pointerLockElement !== "undefined";
114
139
 
115
- // detect touch capabilities
116
- device.touch = device.TouchEvent || device.PointerEvent;
140
+ /**
141
+ * Browser device orientation
142
+ * @name hasDeviceOrientation
143
+ * @memberof device
144
+ * @readonly
145
+ * @public
146
+ * @type {boolean}
147
+ */
148
+ export const hasDeviceOrientation = !!globalThis.DeviceOrientationEvent;
117
149
 
118
- // max amount of touch points ; always at least return 1 (e.g. headless chrome will return 0)
119
- device.maxTouchPoints = device.touch ? (device.PointerEvent ? globalThis.navigator.maxTouchPoints || 1 : 10) : 1;
150
+ /**
151
+ * Supports the ScreenOrientation API
152
+ * @name screenOrientation
153
+ * @memberof device
154
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/onchange
155
+ * @type {boolean}
156
+ * @readonly
157
+ * @public
158
+ */
159
+ export const screenOrientation = (typeof screen !== "undefined") && (typeof screen.orientation !== "undefined");
120
160
 
121
- // detect wheel event support
122
- // Modern browsers support "wheel", Webkit and IE support at least "mousewheel
123
- device.wheel = typeof globalThis.document !== "undefined" && "onwheel" in globalThis.document.createElement("div");
161
+ /**
162
+ * Browser accelerometer capabilities
163
+ * @name hasAccelerometer
164
+ * @memberof device
165
+ * @readonly
166
+ * @public
167
+ * @type {boolean}
168
+ */
169
+ export const hasAccelerometer = !!globalThis.DeviceMotionEvent;
124
170
 
125
- // pointerlock detection (pointerLockElement can be null when the feature is supported)
126
- device.hasPointerLockSupport = typeof globalThis.document !== "undefined" && typeof globalThis.document.pointerLockElement !== "undefined";
171
+ /**
172
+ * Browser full screen support
173
+ * @name hasFullscreenSupport
174
+ * @memberof device
175
+ * @type {boolean}
176
+ * @readonly
177
+ * @public
178
+ */
179
+ export const hasFullscreenSupport = typeof globalThis.document !== "undefined" && (prefixed("fullscreenEnabled", globalThis.document) || globalThis.document.mozFullScreenEnabled);
127
180
 
128
- // device orientation and motion detection
129
- device.hasDeviceOrientation = !!globalThis.DeviceOrientationEvent;
130
- device.hasAccelerometer = !!globalThis.DeviceMotionEvent;
181
+ if (hasFullscreenSupport === true) {
182
+ globalThis.document.exitFullscreen = prefixed("cancelFullScreen", globalThis.document) || prefixed("exitFullscreen", globalThis.document);
183
+ }
131
184
 
132
- // support the ScreenOrientation API
133
- device.ScreenOrientation = (typeof screen !== "undefined") &&
134
- (typeof screen.orientation !== "undefined");
185
+ /**
186
+ * Device WebAudio Support
187
+ * @name hasWebAudio
188
+ * @memberof device
189
+ * @type {boolean}
190
+ * @readonly
191
+ * @public
192
+ */
193
+ export const hasWebAudio = !!(globalThis.AudioContext || globalThis.webkitAudioContext);
135
194
 
136
- // fullscreen api detection & polyfill when possible
137
- device.hasFullscreenSupport = typeof globalThis.document !== "undefined" && (prefixed("fullscreenEnabled", globalThis.document) || globalThis.document.mozFullScreenEnabled);
195
+ /**
196
+ * Device HTML5Audio Support
197
+ * @name hasHTML5Audio
198
+ * @memberof device
199
+ * @type {boolean}
200
+ * @readonly
201
+ * @public
202
+ */
203
+ export const hasHTML5Audio = (typeof globalThis.Audio !== "undefined");
138
204
 
139
- if (device.hasFullscreenSupport === true) {
140
- globalThis.document.exitFullscreen = typeof globalThis.document !== "undefined" && (prefixed("cancelFullScreen", globalThis.document) || prefixed("exitFullscreen", globalThis.document));
141
- }
205
+ /**
206
+ * Returns true if the browser/device has audio capabilities.
207
+ * @name sound
208
+ * @memberof device
209
+ * @type {boolean}
210
+ * @readonly
211
+ * @public
212
+ */
213
+ export const sound = hasWebAudio || hasHTML5Audio;
142
214
 
215
+ /**
216
+ * Browser Local Storage capabilities <br>
217
+ * (this flag will be set to false if cookies are blocked)
218
+ * @name localStorage
219
+ * @memberof device
220
+ * @readonly
221
+ * @public
222
+ * @type {boolean}
223
+ */
224
+ export const localStorage = hasLocalStorage();
143
225
 
144
- // web Audio detection
145
- device.hasWebAudio = !!(globalThis.AudioContext || globalThis.webkitAudioContext);
226
+ /**
227
+ * equals to true if the device browser supports OffScreenCanvas.
228
+ * @name offscreenCanvas
229
+ * @memberof device
230
+ * @type {boolean}
231
+ * @readonly
232
+ * @public
233
+ */
234
+ export const offscreenCanvas = hasOffscreenCanvas();
146
235
 
147
- try {
148
- device.localStorage = !!globalThis.localStorage;
149
- } catch (e) {
150
- // the above generates an exception when cookies are blocked
151
- device.localStorage = false;
236
+ /**
237
+ * Browser Base64 decoding capability
238
+ * @name nativeBase64
239
+ * @memberof device
240
+ * @type {boolean}
241
+ * @readonly
242
+ * @public
243
+ */
244
+ export const nativeBase64 = (typeof(globalThis.atob) === "function");
245
+
246
+ /**
247
+ * a string representing the preferred language of the user, usually the language of the browser UI.
248
+ * (will default to "en" if the information is not available)
249
+ * @name language
250
+ * @memberof device
251
+ * @type {string}
252
+ * @readonly
253
+ * @public
254
+ * @see http://www.w3schools.com/tags/ref_language_codes.asp
255
+ */
256
+ export const language = typeof globalThis.navigator !== "undefined" ? globalThis.navigator.language || globalThis.navigator.browserLanguage || globalThis.navigator.userLanguage || "en" : "en";
257
+
258
+ /**
259
+ * Ratio of the resolution in physical pixels to the resolution in CSS pixels for the current display device.
260
+ * @name devicePixelRatio
261
+ * @memberof device
262
+ * @type {number}
263
+ * @readonly
264
+ * @public
265
+ */
266
+ export const devicePixelRatio = globalThis.devicePixelRatio || 1;
267
+
268
+ /**
269
+ * equals to true if a mobile device.
270
+ * (Android | iPhone | iPad | iPod | BlackBerry | Windows Phone | Kindle)
271
+ * @name isMobile
272
+ * @memberof device
273
+ * @type {boolean}
274
+ * @readonly
275
+ * @public
276
+ */
277
+ export const isMobile = platform.isMobile;
278
+
279
+ /**
280
+ * contains the g-force acceleration along the x-axis.
281
+ * @name accelerationX
282
+ * @memberof device
283
+ * @type {number}
284
+ * @readonly
285
+ * @public
286
+ * @see device.watchAccelerometer
287
+ */
288
+ export let accelerationX = 0;
289
+
290
+ /**
291
+ * contains the g-force acceleration along the y-axis.
292
+ * @name accelerationY
293
+ * @memberof device
294
+ * @type {number}
295
+ * @readonly
296
+ * @public
297
+ * @see device.watchAccelerometer
298
+ */
299
+ export let accelerationY = 0;
300
+
301
+ /**
302
+ * contains the g-force acceleration along the z-axis.
303
+ * @name accelerationZ
304
+ * @memberof device
305
+ * @type {number}
306
+ * @readonly
307
+ * @public
308
+ * @see device.watchAccelerometer
309
+ */
310
+ export let accelerationZ = 0;
311
+
312
+ /**
313
+ * Device orientation Gamma property. Gives angle on tilting a portrait held phone left or right
314
+ * @name gamma
315
+ * @memberof device
316
+ * @type {number}
317
+ * @readonly
318
+ * @public
319
+ * @see device.watchDeviceOrientation
320
+ */
321
+ export let gamma = 0;
322
+
323
+ /**
324
+ * Device orientation Beta property. Gives angle on tilting a portrait held phone forward or backward
325
+ * @name beta
326
+ * @memberof device
327
+ * @type {number}
328
+ * @readonly
329
+ * @public
330
+ * @see device.watchDeviceOrientation
331
+ */
332
+ export let beta = 0;
333
+
334
+ /**
335
+ * Device orientation Alpha property. Gives angle based on the rotation of the phone around its z axis.
336
+ * The z-axis is perpendicular to the phone, facing out from the center of the screen.
337
+ * @name alpha
338
+ * @memberof device
339
+ * @type {number}
340
+ * @readonly
341
+ * @public
342
+ * @see device.watchDeviceOrientation
343
+ */
344
+ export let alpha = 0;
345
+
346
+ /**
347
+ * Specify whether to pause the game when losing focus
348
+ * @name pauseOnBlur
349
+ * @memberof device
350
+ * @type {boolean}
351
+ * @public
352
+ * @default true
353
+ */
354
+ export let pauseOnBlur = true;
355
+
356
+ /**
357
+ * Specify whether to unpause the game when gaining focus
358
+ * @name resumeOnFocus
359
+ * @memberof device
360
+ * @type {boolean}
361
+ * @public
362
+ * @default true
363
+ */
364
+ export let resumeOnFocus = true;
365
+
366
+ /**
367
+ * Specify whether to automatically bring the window to the front
368
+ * @name autoFocus
369
+ * @memberof device
370
+ * @type {boolean}
371
+ * @public
372
+ * @default true
373
+ */
374
+ export let autoFocus = true;
375
+
376
+ /**
377
+ * Specify whether to stop the game when losing focus or not.
378
+ * The engine restarts on focus if this is enabled.
379
+ * @name stopOnBlur
380
+ * @memberof device
381
+ * @type {boolean}
382
+ * @public
383
+ * @default false
384
+ */
385
+ export let stopOnBlur = false;
386
+
387
+ /**
388
+ * specify a function to execute when the Device is fully loaded and ready
389
+ * @function onReady
390
+ * @memberof device
391
+ * @public
392
+ * @param {Function} fn the function to be executed
393
+ * @example
394
+ * // small game skeleton
395
+ * var game = {
396
+ * // called by the me.device.onReady function
397
+ * onload = function () {
398
+ * // init video
399
+ * if (!me.video.init('screen', 640, 480, true)) {
400
+ * alert("Sorry but your browser does not support html 5 canvas.");
401
+ * return;
402
+ * }
403
+ *
404
+ * // initialize the "audio"
405
+ * me.audio.init("mp3,ogg");
406
+ *
407
+ * // set callback for ressources loaded event
408
+ * me.loader.onload = this.loaded.bind(this);
409
+ *
410
+ * // set all ressources to be loaded
411
+ * me.loader.preload(game.assets);
412
+ *
413
+ * // load everything & display a loading screen
414
+ * me.state.change(me.state.LOADING);
415
+ * };
416
+ *
417
+ * // callback when everything is loaded
418
+ * loaded = function () {
419
+ * // define stuff
420
+ * // ....
421
+ *
422
+ * // change to the menu screen
423
+ * me.state.change(me.state.PLAY);
424
+ * }
425
+ * }; // game
426
+ *
427
+ * // "bootstrap"
428
+ * me.device.onReady(function () {
429
+ * game.onload();
430
+ * });
431
+ */
432
+ export function onReady(fn) {
433
+ DOMContentLoaded(fn);
434
+ };
435
+
436
+ /**
437
+ * enable/disable swipe on WebView.
438
+ * @function enableSwipe
439
+ * @memberof device
440
+ * @public
441
+ * @param {boolean} [enable=true] enable or disable swipe.
442
+ */
443
+ export function enableSwipe(enable) {
444
+ let moveEvent = pointerEvent ? "pointermove" : (touchEvent ? "touchmove" : "mousemove");
445
+ if (enable !== false) {
446
+ if (swipeEnabled === false) {
447
+ globalThis.document.removeEventListener(moveEvent, disableSwipeFn);
448
+ swipeEnabled = true;
449
+ }
450
+ } else if (swipeEnabled === true) {
451
+ globalThis.document.addEventListener(moveEvent, disableSwipeFn, { passive: false });
452
+ swipeEnabled = false;
152
453
  }
454
+ };
153
455
 
154
- try {
155
- // some browser (e.g. Safari) implements WebGL1 and WebGL2 contexts only
156
- // https://bugzilla.mozilla.org/show_bug.cgi?id=801176
157
- device.OffscreenCanvas =
158
- (typeof globalThis.OffscreenCanvas !== "undefined") &&
159
- ((new OffscreenCanvas(0, 0).getContext( "2d" )) !== null);
160
- } catch (e) {
161
- device.OffscreenCanvas = false;
456
+ /**
457
+ * Returns true if the browser/device is in full screen mode.
458
+ * @function isFullscreen
459
+ * @memberof device
460
+ * @public
461
+ * @returns {boolean}
462
+ */
463
+ export function isFullscreen() {
464
+ if (hasFullscreenSupport) {
465
+ return !!(prefixed("fullscreenElement", document) || document.mozFullScreenElement);
466
+ } else {
467
+ return false;
468
+ }
469
+ };
470
+
471
+ /**
472
+ * Triggers a fullscreen request. Requires fullscreen support from the browser/device.
473
+ * @function requestFullscreen
474
+ * @memberof device
475
+ * @public
476
+ * @param {object} [element=default canvas object] the element to be set in full-screen mode.
477
+ * @example
478
+ * // add a keyboard shortcut to toggle Fullscreen mode on/off
479
+ * me.input.bindKey(me.input.KEY.F, "toggleFullscreen");
480
+ * me.event.on(me.event.KEYDOWN, function (action, keyCode, edge) {
481
+ * // toggle fullscreen on/off
482
+ * if (action === "toggleFullscreen") {
483
+ * me.device.requestFullscreen();
484
+ * } else {
485
+ * me.device.exitFullscreen();
486
+ * }
487
+ * });
488
+ */
489
+ export function requestFullscreen(element) {
490
+ if (hasFullscreenSupport && !isFullscreen()) {
491
+ element = element || getParent();
492
+ element.requestFullscreen = prefixed("requestFullscreen", element) || element.mozRequestFullScreen;
493
+ element.requestFullscreen();
162
494
  }
495
+ };
163
496
 
164
- if (typeof globalThis.addEventListener === "function") {
165
- // set pause/stop action on losing focus
166
- globalThis.addEventListener("blur", function () {
167
- if (device.stopOnBlur) {
168
- state.stop(true);
169
- }
170
- if (device.pauseOnBlur) {
171
- state.pause(true);
172
- }
173
- }, false);
174
- // set restart/resume action on gaining focus
175
- globalThis.addEventListener("focus", function () {
176
- if (device.stopOnBlur) {
177
- state.restart(true);
178
- }
179
- if (device.resumeOnFocus) {
180
- state.resume(true);
181
- }
182
- // force focus if autofocus is on
183
- if (device.autoFocus) {
184
- device.focus();
185
- }
186
- }, false);
497
+ /**
498
+ * Exit fullscreen mode. Requires fullscreen support from the browser/device.
499
+ * @function exitFullscreen
500
+ * @memberof device
501
+ * @public
502
+ */
503
+ export function exitFullscreen() {
504
+ if (hasFullscreenSupport && isFullscreen()) {
505
+ document.exitFullscreen();
187
506
  }
507
+ };
188
508
 
189
- if (typeof globalThis.document !== "undefined") {
190
- // Set the name of the hidden property and the change event for visibility
191
- var hidden, visibilityChange;
192
- if (typeof globalThis.document.hidden !== "undefined") {
193
- // Opera 12.10 and Firefox 18 and later support
194
- hidden = "hidden";
195
- visibilityChange = "visibilitychange";
196
- } else if (typeof globalThis.document.mozHidden !== "undefined") {
197
- hidden = "mozHidden";
198
- visibilityChange = "mozvisibilitychange";
199
- } else if (typeof globalThis.document.msHidden !== "undefined") {
200
- hidden = "msHidden";
201
- visibilityChange = "msvisibilitychange";
202
- } else if (typeof globalThis.document.webkitHidden !== "undefined") {
203
- hidden = "webkitHidden";
204
- visibilityChange = "webkitvisibilitychange";
509
+ /**
510
+ * Return a string representing the orientation of the device screen.
511
+ * It can be "any", "natural", "landscape", "portrait", "portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary"
512
+ * @function getScreenOrientation
513
+ * @memberof device
514
+ * @public
515
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Screen/orientation
516
+ * @returns {string} the screen orientation
517
+ */
518
+ export function getScreenOrientation() {
519
+ const PORTRAIT = "portrait";
520
+ const LANDSCAPE = "landscape";
521
+
522
+ let screen = globalThis.screen;
523
+
524
+ // first try using "standard" values
525
+ if (screenOrientation === true) {
526
+ let orientation = prefixed("orientation", screen);
527
+ if (typeof orientation !== "undefined" && typeof orientation.type === "string") {
528
+ // Screen Orientation API specification
529
+ return orientation.type;
530
+ } else if (typeof orientation === "string") {
531
+ // moz/ms-orientation are strings
532
+ return orientation;
205
533
  }
534
+ }
206
535
 
207
- // register on the event if supported
208
- if (typeof (visibilityChange) === "string") {
209
- // add the corresponding event listener
210
- globalThis.document.addEventListener(visibilityChange,
211
- function () {
212
- if (globalThis.document[hidden]) {
213
- if (device.stopOnBlur) {
214
- state.stop(true);
215
- }
216
- if (device.pauseOnBlur) {
217
- state.pause(true);
218
- }
219
- } else {
220
- if (device.stopOnBlur) {
221
- state.restart(true);
222
- }
223
- if (device.resumeOnFocus) {
224
- state.resume(true);
225
- }
226
- }
227
- }, false
228
- );
536
+ // check using the deprecated API
537
+ if (typeof globalThis.orientation === "number") {
538
+ return (Math.abs(globalThis.orientation) === 90) ? LANDSCAPE : PORTRAIT;
539
+ }
540
+
541
+ // fallback to window size check
542
+ return (globalThis.outerWidth > globalThis.outerHeight) ? LANDSCAPE : PORTRAIT;
543
+ };
544
+
545
+ /**
546
+ * locks the device screen into the specified orientation.<br>
547
+ * This method only works for installed Web apps or for Web pages in full-screen mode.
548
+ * @function lockOrientation
549
+ * @memberof device
550
+ * @public
551
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation
552
+ * @param {string|string[]} orientation The orientation into which to lock the screen.
553
+ * @returns {boolean} true if the orientation was unsuccessfully locked
554
+ */
555
+ export function lockOrientation(orientation) {
556
+ let screen = globalThis.screen;
557
+ if (typeof screen !== "undefined") {
558
+ let _lockOrientation = prefixed("lockOrientation", screen);
559
+ if (typeof _lockOrientation !== "undefined") {
560
+ return _lockOrientation(orientation);
229
561
  }
230
562
  }
563
+ return false;
564
+ };
231
565
 
232
- // Mobile browser hacks
233
- if (device.isMobile) {
234
- // Prevent the webview from moving on a swipe
235
- device.enableSwipe(false);
566
+ /**
567
+ * unlocks the device screen into the specified orientation.<br>
568
+ * This method only works for installed Web apps or for Web pages in full-screen mode.
569
+ * @function unlockOrientation
570
+ * @memberof device
571
+ * @public
572
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation
573
+ * @returns {boolean} true if the orientation was unsuccessfully unlocked
574
+ */
575
+ export function unlockOrientation() {
576
+ let screen = globalThis.screen;
577
+ if (typeof screen !== "undefined") {
578
+ let _unlockOrientation = prefixed("unlockOrientation", screen);
579
+ if (typeof _unlockOrientation !== "undefined") {
580
+ return _unlockOrientation();
581
+ }
236
582
  }
583
+ return false;
584
+ };
237
585
 
586
+ /**
587
+ * return true if the device screen orientation is in Portrait mode
588
+ * @function isPortrait
589
+ * @memberof device
590
+ * @public
591
+ * @returns {boolean}
592
+ */
593
+ export function isPortrait() {
594
+ return getScreenOrientation().includes("portrait");
238
595
  };
239
596
 
597
+ /**
598
+ * return true if the device screen orientation is in Portrait mode
599
+ * @function isLandscape
600
+ * @memberof device
601
+ * @public
602
+ * @returns {boolean}
603
+ */
604
+ export function isLandscape() {
605
+ return getScreenOrientation().includes("landscape");
606
+ };
240
607
 
241
- // Initialize me.timer on Boot event
242
- event.on(event.BOOT, () => {
243
- _checkCapabilities();
244
- });
608
+ /**
609
+ * return the device storage
610
+ * @function getStorage
611
+ * @memberof device
612
+ * @public
613
+ * @see save
614
+ * @param {string} [type="local"]
615
+ * @returns {object} a reference to the device storage
616
+ */
617
+ export function getStorage(type = "local") {
618
+ switch (type) {
619
+ case "local" :
620
+ return save;
245
621
 
622
+ default :
623
+ throw new Error("storage type " + type + " not supported");
624
+ }
625
+ };
246
626
 
247
- // public export
248
627
  /**
249
- * The device capabilities and specific events
250
- *
251
- * @namespace
628
+ * return the parent DOM element for the given parent name or HTMLElement object
629
+ * @function getParentElement
630
+ * @memberof device
631
+ * @public
632
+ * @param {string|HTMLElement} element the parent element name or a HTMLElement object
633
+ * @returns {HTMLElement} the parent Element
252
634
  */
253
- let device = {
254
-
255
- /**
256
- * the `ua` read-only property returns the user agent string for the current browser.
257
- * @type {string}
258
- * @readonly
259
- * @name ua
260
- */
261
- ua : typeof globalThis.navigator !== "undefined" ? globalThis.navigator.userAgent : "",
262
-
263
- /**
264
- * Browser Local Storage capabilities <br>
265
- * (this flag will be set to false if cookies are blocked)
266
- * @type {boolean}
267
- * @readonly
268
- * @name localStorage
269
- */
270
- localStorage : false,
271
-
272
- /**
273
- * Browser accelerometer capabilities
274
- * @type {boolean}
275
- * @readonly
276
- * @name hasAccelerometer
277
- */
278
- hasAccelerometer : false,
279
-
280
- /**
281
- * Browser device orientation
282
- * @type {boolean}
283
- * @readonly
284
- * @name hasDeviceOrientation
285
- */
286
- hasDeviceOrientation : false,
287
-
288
- /**
289
- * Supports the ScreenOrientation API
290
- * @see https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/onchange
291
- * @type {boolean}
292
- * @readonly
293
- * @name ScreenOrientation
294
- */
295
- ScreenOrientation : false,
296
-
297
- /**
298
- * Browser full screen support
299
- * @type {boolean}
300
- * @readonly
301
- * @name hasFullscreenSupport
302
- */
303
- hasFullscreenSupport : false,
304
-
305
- /**
306
- * Browser pointerlock api support
307
- * @type {boolean}
308
- * @readonly
309
- * @name hasPointerLockSupport
310
- */
311
- hasPointerLockSupport : false,
312
-
313
- /**
314
- * Device WebAudio Support
315
- * @type {boolean}
316
- * @readonly
317
- * @name hasWebAudio
318
- */
319
- hasWebAudio : false,
320
-
321
- /**
322
- * Browser Base64 decoding capability
323
- * @type {boolean}
324
- * @readonly
325
- * @name nativeBase64
326
- */
327
- nativeBase64 : (typeof(globalThis.atob) === "function"),
328
-
329
- /**
330
- * Return the maximum number of simultaneous touch contact points are supported by the current device.
331
- * @type {number}
332
- * @readonly
333
- * @name maxTouchPoints
334
- * @example
335
- * if (me.device.maxTouchPoints > 1) {
336
- * // device supports multi-touch
337
- * }
338
- */
339
- maxTouchPoints : 1,
340
-
341
- /**
342
- * Touch capabilities
343
- * @type {boolean}
344
- * @readonly
345
- * @name touch
346
- */
347
- touch : false,
348
-
349
- /**
350
- * W3C standard wheel events
351
- * @type {boolean}
352
- * @readonly
353
- * @name wheel
354
- */
355
- wheel : false,
356
-
357
- /**
358
- * equals to true if a mobile device <br>
359
- * (Android | iPhone | iPad | iPod | BlackBerry | Windows Phone | Kindle)
360
- * @type {boolean}
361
- * @readonly
362
- * @name isMobile
363
- */
364
- isMobile : false,
365
-
366
- /**
367
- * equals to true if the device is an iOS platform.
368
- * @type {boolean}
369
- * @readonly
370
- * @name iOS
371
- */
372
- iOS : false,
373
-
374
- /**
375
- * equals to true if the device is an Android platform.
376
- * @type {boolean}
377
- * @readonly
378
- * @name android
379
- */
380
- android : false,
381
-
382
- /**
383
- * equals to true if the device is an Android 2.x platform.
384
- * @type {boolean}
385
- * @readonly
386
- * @name android2
387
- */
388
- android2 : false,
389
-
390
- /**
391
- * equals to true if the device is a Linux platform.
392
- * @type {boolean}
393
- * @readonly
394
- * @name linux
395
- */
396
- linux : false,
397
-
398
- /**
399
- * equals to true if the game is running under Ejecta.
400
- * @type {boolean}
401
- * @readonly
402
- * @see http://impactjs.com/ejecta
403
- * @name ejecta
404
- */
405
- ejecta : false,
406
-
407
- /**
408
- * equals to true if the is running under Wechat.
409
- * @type {boolean}
410
- * @readonly
411
- * @name isWeixin
412
- */
413
- isWeixin : false,
414
-
415
- /**
416
- * equals to true if running under node.js
417
- * @type {boolean}
418
- * @readonly
419
- * @name nodeJS
420
- */
421
- nodeJS : (typeof process !== "undefined") && (process.release.name === "node"),
422
-
423
- /**
424
- * equals to true if the device is running on ChromeOS.
425
- * @type {boolean}
426
- * @readonly
427
- * @name chromeOS
428
- */
429
- chromeOS : false,
430
-
431
- /**
432
- * equals to true if the device is a Windows Phone platform.
433
- * @type {boolean}
434
- * @readonly
435
- * @name wp
436
- */
437
- wp : false,
438
-
439
- /**
440
- * equals to true if the device is a BlackBerry platform.
441
- * @type {boolean}
442
- * @readonly
443
- * @name BlackBerry
444
- */
445
- BlackBerry : false,
446
-
447
- /**
448
- * equals to true if the device is a Kindle platform.
449
- * @type {boolean}
450
- * @readonly
451
- * @name Kindle
452
- */
453
- Kindle : false,
454
-
455
- /**
456
- * contains the g-force acceleration along the x-axis.
457
- * @public
458
- * @type {number}
459
- * @readonly
460
- * @name accelerationX
461
- * @see device.watchAccelerometer
462
- */
463
- accelerationX : 0,
464
-
465
- /**
466
- * contains the g-force acceleration along the y-axis.
467
- * @public
468
- * @type {number}
469
- * @readonly
470
- * @name accelerationY
471
- * @see device.watchAccelerometer
472
- */
473
- accelerationY : 0,
474
-
475
- /**
476
- * contains the g-force acceleration along the z-axis.
477
- * @public
478
- * @type {number}
479
- * @readonly
480
- * @name accelerationZ
481
- * @see device.watchAccelerometer
482
- */
483
- accelerationZ : 0,
484
-
485
- /**
486
- * Device orientation Gamma property. Gives angle on tilting a portrait held phone left or right
487
- * @public
488
- * @type {number}
489
- * @readonly
490
- * @name gamma
491
- * @see device.watchDeviceOrientation
492
- */
493
- gamma : 0,
494
-
495
- /**
496
- * Device orientation Beta property. Gives angle on tilting a portrait held phone forward or backward
497
- * @public
498
- * @type {number}
499
- * @readonly
500
- * @name beta
501
- * @see device.watchDeviceOrientation
502
- */
503
- beta: 0,
504
-
505
- /**
506
- * Device orientation Alpha property. Gives angle based on the rotation of the phone around its z axis.
507
- * The z-axis is perpendicular to the phone, facing out from the center of the screen.
508
- * @public
509
- * @type {number}
510
- * @readonly
511
- * @name alpha
512
- * @see device.watchDeviceOrientation
513
- */
514
- alpha : 0,
515
-
516
- /**
517
- * a string representing the preferred language of the user, usually the language of the browser UI.
518
- * (will default to "en" if the information is not available)
519
- * @public
520
- * @type {string}
521
- * @readonly
522
- * @see http://www.w3schools.com/tags/ref_language_codes.asp
523
- * @name language
524
- */
525
- language : typeof globalThis.navigator !== "undefined" ? globalThis.navigator.language || globalThis.navigator.browserLanguage || globalThis.navigator.userLanguage || "en" : "en",
526
-
527
- /**
528
- * Specify whether to pause the game when losing focus
529
- * @type {boolean}
530
- * @default true
531
- */
532
- pauseOnBlur : true,
533
-
534
- /**
535
- * Specify whether to unpause the game when gaining focus
536
- * @type {boolean}
537
- * @default true
538
- */
539
- resumeOnFocus : true,
540
-
541
- /**
542
- * Specify whether to automatically bring the window to the front
543
- * @type {boolean}
544
- * @default true
545
- */
546
- autoFocus : true,
547
-
548
- /**
549
- * Specify whether to stop the game when losing focus or not.
550
- * The engine restarts on focus if this is enabled.
551
- * @type {boolean}
552
- * @default false
553
- */
554
- stopOnBlur : false,
555
-
556
- /**
557
- * equals to true if the device browser supports OffScreenCanvas.
558
- * @type {boolean}
559
- * @readonly
560
- * @name OffScreenCanvas
561
- */
562
- OffscreenCanvas : false,
563
-
564
-
565
- /**
566
- * specify a function to execute when the Device is fully loaded and ready
567
- * @function device.onReady
568
- * @param {Function} fn the function to be executed
569
- * @example
570
- * // small game skeleton
571
- * var game = {
572
- * // called by the me.device.onReady function
573
- * onload : function () {
574
- * // init video
575
- * if (!me.video.init('screen', 640, 480, true)) {
576
- * alert("Sorry but your browser does not support html 5 canvas.");
577
- * return;
578
- * }
579
- *
580
- * // initialize the "audio"
581
- * me.audio.init("mp3,ogg");
582
- *
583
- * // set callback for ressources loaded event
584
- * me.loader.onload = this.loaded.bind(this);
585
- *
586
- * // set all ressources to be loaded
587
- * me.loader.preload(game.assets);
588
- *
589
- * // load everything & display a loading screen
590
- * me.state.change(me.state.LOADING);
591
- * },
592
- *
593
- * // callback when everything is loaded
594
- * loaded : function () {
595
- * // define stuff
596
- * // ....
597
- *
598
- * // change to the menu screen
599
- * me.state.change(me.state.PLAY);
600
- * }
601
- * }, // game
602
- *
603
- * // "bootstrap"
604
- * me.device.onReady(function () {
605
- * game.onload();
606
- * });
607
- */
608
- onReady(fn) {
609
- // If the DOM is already ready
610
- if (isReady) {
611
- // Execute the function immediately
612
- fn.call(globalThis, []);
613
- }
614
- else {
615
- // Add the function to the wait list
616
- readyList.push(fn);
617
-
618
- // attach listeners if not yet done
619
- if (!readyBound) {
620
- // directly call domReady if document is already "ready"
621
- if (device.nodeJS === true || (typeof globalThis.document !== "undefined" && globalThis.document.readyState === "complete")) {
622
- // defer the fn call to ensure our script is fully loaded
623
- globalThis.setTimeout(_domReady, 0);
624
- }
625
- else {
626
- if (typeof globalThis.document !== "undefined" && typeof globalThis.document.addEventListener === "function") {
627
- // Use the handy event callback
628
- globalThis.document.addEventListener("DOMContentLoaded", _domReady, false);
629
- }
630
- // A fallback to globalThis.onload, that will always work
631
- globalThis.addEventListener("load", _domReady, false);
632
- }
633
- readyBound = true;
634
- }
635
- }
636
- },
637
-
638
- /**
639
- * enable/disable swipe on WebView.
640
- * @function device.enableSwipe
641
- * @param {boolean} [enable=true] enable or disable swipe.
642
- */
643
- enableSwipe(enable) {
644
- var moveEvent = device.PointerEvent ? "pointermove" : (device.TouchEvent ? "touchmove" : "mousemove");
645
- if (enable !== false) {
646
- if (swipeEnabled === false) {
647
- globalThis.document.removeEventListener(moveEvent, _disableSwipeFn);
648
- swipeEnabled = true;
649
- }
650
- } else if (swipeEnabled === true) {
651
- globalThis.document.addEventListener(moveEvent, _disableSwipeFn, { passive: false });
652
- swipeEnabled = false;
653
- }
654
- },
655
-
656
- /**
657
- * Triggers a fullscreen request. Requires fullscreen support from the browser/device.
658
- * @function device.requestFullscreen
659
- * @param {object} [element=default canvas object] the element to be set in full-screen mode.
660
- * @example
661
- * // add a keyboard shortcut to toggle Fullscreen mode on/off
662
- * me.input.bindKey(me.input.KEY.F, "toggleFullscreen");
663
- * me.event.on(me.event.KEYDOWN, function (action, keyCode, edge) {
664
- * // toggle fullscreen on/off
665
- * if (action === "toggleFullscreen") {
666
- * if (!me.device.isFullscreen) {
667
- * me.device.requestFullscreen();
668
- * } else {
669
- * me.device.exitFullscreen();
670
- * }
671
- * }
672
- * });
673
- */
674
- requestFullscreen(element) {
675
- if (this.hasFullscreenSupport) {
676
- element = element || getParent();
677
- element.requestFullscreen = prefixed("requestFullscreen", element) ||
678
- element.mozRequestFullScreen;
679
-
680
- element.requestFullscreen();
681
- }
682
- },
683
-
684
- /**
685
- * Exit fullscreen mode. Requires fullscreen support from the browser/device.
686
- * @function device.exitFullscreen
687
- */
688
- exitFullscreen() {
689
- if (this.hasFullscreenSupport) {
690
- document.exitFullscreen();
691
- }
692
- },
693
-
694
- /**
695
- * Return a string representing the orientation of the device screen.
696
- * It can be "any", "natural", "landscape", "portrait", "portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary"
697
- * @function device.getScreenOrientation
698
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Screen/orientation
699
- * @returns {string} the screen orientation
700
- */
701
- getScreenOrientation() {
702
- var PORTRAIT = "portrait";
703
- var LANDSCAPE = "landscape";
704
-
705
- var screen = globalThis.screen;
706
-
707
- // first try using "standard" values
708
- if (this.ScreenOrientation === true) {
709
- var orientation = prefixed("orientation", screen);
710
- if (typeof orientation !== "undefined" && typeof orientation.type === "string") {
711
- // Screen Orientation API specification
712
- return orientation.type;
713
- } else if (typeof orientation === "string") {
714
- // moz/ms-orientation are strings
715
- return orientation;
716
- }
717
- }
635
+ export function getParentElement(element) {
636
+ let target = getElement(element);
718
637
 
719
- // check using the deprecated API
720
- if (typeof globalThis.orientation === "number") {
721
- return (Math.abs(globalThis.orientation) === 90) ? LANDSCAPE : PORTRAIT;
722
- }
638
+ if (target.parentNode !== null) {
639
+ target = target.parentNode;
640
+ }
723
641
 
724
- // fallback to window size check
725
- return (globalThis.outerWidth > globalThis.outerHeight) ? LANDSCAPE : PORTRAIT;
726
- },
727
-
728
- /**
729
- * locks the device screen into the specified orientation.<br>
730
- * This method only works for installed Web apps or for Web pages in full-screen mode.
731
- * @function device.lockOrientation
732
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation
733
- * @param {string|string[]} orientation The orientation into which to lock the screen.
734
- * @returns {boolean} true if the orientation was unsuccessfully locked
735
- */
736
- lockOrientation(orientation) {
737
- var screen = globalThis.screen;
738
- if (typeof screen !== "undefined") {
739
- var _lockOrientation = prefixed("lockOrientation", screen);
740
- if (typeof _lockOrientation !== "undefined") {
741
- return _lockOrientation(orientation);
742
- }
743
- }
744
- return false;
745
- },
746
-
747
- /**
748
- * unlocks the device screen into the specified orientation.<br>
749
- * This method only works for installed Web apps or for Web pages in full-screen mode.
750
- * @function device.unlockOrientation
751
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation
752
- * @returns {boolean} true if the orientation was unsuccessfully unlocked
753
- */
754
- unlockOrientation() {
755
- var screen = globalThis.screen;
756
- if (typeof screen !== "undefined") {
757
- var _unlockOrientation = prefixed("unlockOrientation", screen);
758
- if (typeof _unlockOrientation !== "undefined") {
759
- return _unlockOrientation();
760
- }
761
- }
762
- return false;
763
- },
764
-
765
- /**
766
- * return true if the device screen orientation is in Portrait mode
767
- * @function device.isPortrait
768
- * @returns {boolean}
769
- */
770
- isPortrait() {
771
- return this.getScreenOrientation().includes("portrait");
772
- },
773
-
774
- /**
775
- * return true if the device screen orientation is in Portrait mode
776
- * @function device.isLandscape
777
- * @returns {boolean}
778
- */
779
- isLandscape() {
780
- return this.getScreenOrientation().includes("landscape");
781
- },
782
-
783
- /**
784
- * return the device storage
785
- * @function device.getStorage
786
- * @see save
787
- * @param {string} [type="local"]
788
- * @returns {object} a reference to the device storage
789
- */
790
- getStorage(type = "local") {
791
- switch (type) {
792
- case "local" :
793
- return save;
794
-
795
- default :
796
- throw new Error("storage type " + type + " not supported");
797
- }
798
- },
799
-
800
- /**
801
- * return the parent DOM element for the given parent name or HTMLElement object
802
- * @function device.getParentElement
803
- * @param {string|HTMLElement} element the parent element name or a HTMLElement object
804
- * @returns {HTMLElement} the parent Element
805
- */
806
- getParentElement(element) {
807
- var target = this.getElement(element);
808
-
809
- if (target.parentNode !== null) {
810
- target = target.parentNode;
811
- }
642
+ return target;
643
+ };
812
644
 
813
- return target;
814
- },
815
-
816
- /**
817
- * return the DOM element for the given element name or HTMLElement object
818
- * @function device.getElement
819
- * @param {string|HTMLElement} element the parent element name or a HTMLElement object
820
- * @returns {HTMLElement} the corresponding DOM Element or null if not existing
821
- */
822
- getElement(element) {
823
- var target = null;
824
-
825
- if (element !== "undefined") {
826
- if (typeof element === "string") {
827
- target = document.getElementById(element);
828
- } else if (typeof element === "object" && element.nodeType === Node.ELEMENT_NODE) {
829
- target = element;
830
- }
645
+ /**
646
+ * return the DOM element for the given element name or HTMLElement object
647
+ * @function getElement
648
+ * @memberof device
649
+ * @public
650
+ * @param {string|HTMLElement} element the parent element name or a HTMLElement object
651
+ * @returns {HTMLElement} the corresponding DOM Element or null if not existing
652
+ */
653
+ export function getElement(element) {
654
+ let target = null;
655
+
656
+ if (element !== "undefined") {
657
+ if (typeof element === "string") {
658
+ target = document.getElementById(element);
659
+ } else if (typeof element === "object" && element.nodeType === Node.ELEMENT_NODE) {
660
+ target = element;
831
661
  }
662
+ }
832
663
 
833
- // fallback, if invalid target or non HTMLElement object
834
- if (!target) {
835
- //default to document.body
836
- target = document.body;
837
- }
664
+ // fallback, if invalid target or non HTMLElement object
665
+ if (!target) {
666
+ //default to document.body
667
+ target = document.body;
668
+ }
838
669
 
839
- return target;
840
- },
841
-
842
- /**
843
- * returns the size of the given HTMLElement and its position relative to the viewport
844
- * <br><img src="images/element-box-diagram.png"/>
845
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
846
- * @function device.getElementBounds
847
- * @param {string|HTMLElement} element an HTMLElement object
848
- * @returns {DOMRect} the size and position of the element relatively to the viewport
849
- */
850
- getElementBounds(element) {
851
- if (typeof element === "object" && element !== document.body && typeof element.getBoundingClientRect !== "undefined") {
852
- return element.getBoundingClientRect();
853
- } else {
854
- _domRect.width = _domRect.right = globalThis.innerWidth;
855
- _domRect.height = _domRect.bottom = globalThis.innerHeight;
856
- return _domRect;
670
+ return target;
671
+ };
672
+
673
+ /**
674
+ * returns the size of the given HTMLElement and its position relative to the viewport
675
+ * <br><img src="images/element-box-diagram.png"/>
676
+ * @function getElementBounds
677
+ * @memberof device
678
+ * @public
679
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
680
+ * @param {string|HTMLElement} element an HTMLElement object
681
+ * @returns {DOMRect} the size and position of the element relatively to the viewport
682
+ */
683
+ export function getElementBounds(element) {
684
+ if (typeof element === "object" && element !== document.body && typeof element.getBoundingClientRect !== "undefined") {
685
+ return element.getBoundingClientRect();
686
+ } else {
687
+ domRect.width = domRect.right = globalThis.innerWidth;
688
+ domRect.height = domRect.bottom = globalThis.innerHeight;
689
+ return domRect;
690
+ };
691
+ };
692
+
693
+ /**
694
+ * returns the size of the given HTMLElement Parent and its position relative to the viewport
695
+ * <br><img src="images/element-box-diagram.png"/>
696
+ * @function getParentBounds
697
+ * @memberof device
698
+ * @public
699
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
700
+ * @param {string|HTMLElement} element an HTMLElement object
701
+ * @returns {DOMRect} the size and position of the given element parent relative to the viewport
702
+ */
703
+ export function getParentBounds(element) {
704
+ return getElementBounds(getParentElement(element));
705
+ };
706
+
707
+ /**
708
+ * returns true if the device supports WebGL
709
+ * @function isWebGLSupported
710
+ * @memberof device
711
+ * @public
712
+ * @param {object} [options] context creation options
713
+ * @param {boolean} [options.failIfMajorPerformanceCaveat=true] If true, the renderer will switch to CANVAS mode if the performances of a WebGL context would be dramatically lower than that of a native application making equivalent OpenGL calls.
714
+ * @returns {boolean} true if WebGL is supported
715
+ */
716
+ export function isWebGLSupported(options) {
717
+ let _supported = false;
718
+ try {
719
+ let canvas = document.createElement("canvas");
720
+ let ctxOptions = {
721
+ stencil: true,
722
+ failIfMajorPerformanceCaveat: options.failIfMajorPerformanceCaveat
857
723
  };
858
- },
859
-
860
- /**
861
- * returns the size of the given HTMLElement Parent and its position relative to the viewport
862
- * <br><img src="images/element-box-diagram.png"/>
863
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
864
- * @function device.getParentBounds
865
- * @param {string|HTMLElement} element an HTMLElement object
866
- * @returns {DOMRect} the size and position of the given element parent relative to the viewport
867
- */
868
- getParentBounds(element) {
869
- return this.getElementBounds(this.getParentElement(element));
870
- },
871
-
872
- /**
873
- * returns true if the device supports WebGL
874
- * @function device.isWebGLSupported
875
- * @param {object} [options] context creation options
876
- * @param {boolean} [options.failIfMajorPerformanceCaveat=true] If true, the renderer will switch to CANVAS mode if the performances of a WebGL context would be dramatically lower than that of a native application making equivalent OpenGL calls.
877
- * @returns {boolean} true if WebGL is supported
878
- */
879
- isWebGLSupported(options) {
880
- var _supported = false;
881
- try {
882
- var canvas = document.createElement("canvas");
883
- var ctxOptions = {
884
- stencil: true,
885
- failIfMajorPerformanceCaveat : options.failIfMajorPerformanceCaveat
886
- };
887
- _supported = !! (globalThis.WebGLRenderingContext && (canvas.getContext("webgl", ctxOptions) || canvas.getContext("experimental-webgl", ctxOptions)));
888
- } catch (e) {
889
- _supported = false;
890
- }
724
+ _supported = !! (globalThis.WebGLRenderingContext && (canvas.getContext("webgl", ctxOptions) || canvas.getContext("experimental-webgl", ctxOptions)));
725
+ } catch (e) {
726
+ _supported = false;
727
+ }
891
728
 
892
- return _supported;
893
- },
894
-
895
- /**
896
- * return the highest precision format supported by this device for GL Shaders
897
- * @function device.getMaxShaderPrecision
898
- * @param {WebGLRenderingContext} gl
899
- * @returns {boolean} "lowp", "mediump", or "highp"
900
- */
901
- getMaxShaderPrecision(gl) {
902
- if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
903
- gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0) {
904
- return "highp";
905
- }
906
- if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
907
- gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0) {
908
- return "mediump";
909
- }
910
- return "lowp";
911
- },
912
-
913
- /**
914
- * Makes a request to bring this device window to the front.
915
- * @function device.focus
916
- * @example
917
- * if (clicked) {
918
- * me.device.focus();
919
- * }
920
- */
921
- focus() {
922
- if (typeof (globalThis.focus) === "function") {
923
- globalThis.focus();
924
- }
925
- },
926
-
927
-
928
- /**
929
- * event management (Accelerometer)
930
- * http://www.mobilexweb.com/samples/ball.html
931
- * http://www.mobilexweb.com/blog/safari-ios-accelerometer-websockets-html5
932
- * @ignore
933
- */
934
- onDeviceMotion(e) {
935
- // Accelerometer information
936
- this.accelerationX = e.accelerationIncludingGravity.x;
937
- this.accelerationY = e.accelerationIncludingGravity.y;
938
- this.accelerationZ = e.accelerationIncludingGravity.z;
939
- },
940
-
941
- /**
942
- * event management (Accelerometer)
943
- * @ignore
944
- */
945
- onDeviceRotate(e) {
946
- this.gamma = e.gamma;
947
- this.beta = e.beta;
948
- this.alpha = e.alpha;
949
- },
950
-
951
- /**
952
- * Enable monitor of the device accelerator to detect the amount of physical force of acceleration the device is receiving.
953
- * (one some device a first user gesture will be required before calling this function)
954
- * @function device.watchAccelerometer
955
- * @see device.accelerationX
956
- * @see device.accelerationY
957
- * @see device.accelerationZ
958
- * @returns {boolean} false if not supported or permission not granted by the user
959
- * @example
960
- * // try to enable device accelerometer event on user gesture
961
- * me.input.registerPointerEvent("pointerleave", me.game.viewport, function() {
962
- * if (me.device.watchAccelerometer() === true) {
963
- * // Success
964
- * me.input.releasePointerEvent("pointerleave", me.game.viewport);
965
- * } else {
966
- * // ... fail at enabling the device accelerometer event
967
- * }
968
- * });
969
- */
970
- watchAccelerometer() {
971
- if (this.hasAccelerometer && !accelInitialized) {
972
- if (DeviceOrientationEvent && typeof DeviceOrientationEvent.requestPermission === "function") {
973
- DeviceOrientationEvent.requestPermission()
974
- .then(response => {
975
- if (response === "granted") {
976
- // add a listener for the devicemotion event
977
- globalThis.addEventListener("devicemotion", this.onDeviceMotion, false);
978
- accelInitialized = true;
979
- }
980
- }).catch(console.error);
981
- } else {
982
- // add a listener for the devicemotion event
983
- globalThis.addEventListener("devicemotion", this.onDeviceMotion, false);
984
- accelInitialized = true;
985
- }
986
- }
987
- return accelInitialized;
988
- },
989
-
990
- /**
991
- * unwatch Accelerometor event
992
- * @function device.unwatchAccelerometer
993
- */
994
- unwatchAccelerometer() {
995
- if (accelInitialized) {
996
- // remove the listener for the devicemotion event
997
- globalThis.removeEventListener("devicemotion", this.onDeviceMotion, false);
998
- accelInitialized = false;
999
- }
1000
- },
1001
-
1002
- /**
1003
- * Enable monitor of the device orientation to detect the current orientation of the device as compared to the Earth coordinate frame.
1004
- * (one some device a first user gesture will be required before calling this function)
1005
- * @function device.watchDeviceOrientation
1006
- * @see device.alpha
1007
- * @see device.beta
1008
- * @see device.gamma
1009
- * @returns {boolean} false if not supported or permission not granted by the user
1010
- * @example
1011
- * // try to enable device orientation event on user gesture
1012
- * me.input.registerPointerEvent("pointerleave", me.game.viewport, function() {
1013
- * if (me.device.watchDeviceOrientation() === true) {
1014
- * // Success
1015
- * me.input.releasePointerEvent("pointerleave", me.game.viewport);
1016
- * } else {
1017
- * // ... fail at enabling the device orientation event
1018
- * }
1019
- * });
1020
- */
1021
- watchDeviceOrientation() {
1022
- if (this.hasDeviceOrientation && !deviceOrientationInitialized) {
1023
- if (typeof DeviceOrientationEvent.requestPermission === "function") {
1024
- DeviceOrientationEvent.requestPermission()
1025
- .then(response => {
1026
- if (response === "granted") {
1027
- globalThis.addEventListener("deviceorientation", this.onDeviceRotate, false);
1028
- deviceOrientationInitialized = true;
1029
- }
1030
- }).catch(console.error);
1031
- } else {
1032
- globalThis.addEventListener("deviceorientation", this.onDeviceRotate, false);
1033
- deviceOrientationInitialized = true;
1034
- }
1035
- }
1036
- return deviceOrientationInitialized;
1037
- },
1038
-
1039
- /**
1040
- * unwatch Device orientation event
1041
- * @function device.unwatchDeviceOrientation
1042
- */
1043
- unwatchDeviceOrientation() {
1044
- if (deviceOrientationInitialized) {
1045
- globalThis.removeEventListener("deviceorientation", this.onDeviceRotate, false);
1046
- deviceOrientationInitialized = false;
1047
- }
1048
- },
1049
-
1050
- /**
1051
- * the vibrate method pulses the vibration hardware on the device, <br>
1052
- * If the device doesn't support vibration, this method has no effect. <br>
1053
- * If a vibration pattern is already in progress when this method is called,
1054
- * the previous pattern is halted and the new one begins instead.
1055
- * @function device.vibrate
1056
- * @param {number|number[]} pattern pattern of vibration and pause intervals
1057
- * @example
1058
- * // vibrate for 1000 ms
1059
- * me.device.vibrate(1000);
1060
- * // or alternatively
1061
- * me.device.vibrate([1000]);
1062
- * // vibrate for 50 ms, be still for 100 ms, and then vibrate for 150 ms:
1063
- * me.device.vibrate([50, 100, 150]);
1064
- * // cancel any existing vibrations
1065
- * me.device.vibrate(0);
1066
- */
1067
- vibrate(pattern) {
1068
- if (typeof globalThis.navigator !== "undefined" && typeof globalThis.navigator.vibrate === "function") {
1069
- globalThis.navigator.vibrate(pattern);
1070
- }
729
+ return _supported;
730
+ };
731
+
732
+ /**
733
+ * return the highest precision format supported by this device for GL Shaders
734
+ * @function getMaxShaderPrecision
735
+ * @memberof device
736
+ * @public
737
+ * @param {WebGLRenderingContext} gl
738
+ * @returns {boolean} "lowp", "mediump", or "highp"
739
+ */
740
+ export function getMaxShaderPrecision(gl) {
741
+ if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
742
+ gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0) {
743
+ return "highp";
744
+ }
745
+ if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
746
+ gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0) {
747
+ return "mediump";
1071
748
  }
749
+ return "lowp";
750
+ };
1072
751
 
752
+ /**
753
+ * Makes a request to bring this device window to the front.
754
+ * @function focus
755
+ * @memberof device
756
+ * @public
757
+ * @example
758
+ * if (clicked) {
759
+ * me.device.focus();
760
+ * }
761
+ */
762
+ export function focus() {
763
+ if (typeof (globalThis.focus) === "function") {
764
+ globalThis.focus();
765
+ }
1073
766
  };
1074
767
 
1075
768
  /**
1076
- * Ratio of the resolution in physical pixels to the resolution in CSS pixels for the current display device.
1077
- * @name device.devicePixelRatio
769
+ * Enable monitor of the device accelerator to detect the amount of physical force of acceleration the device is receiving.
770
+ * (one some device a first user gesture will be required before calling this function)
771
+ * @function watchAccelerometer
772
+ * @memberof device
1078
773
  * @public
1079
- * @member {number}
1080
- * @readonly
1081
- * @returns {number}
774
+ * @see device.accelerationX
775
+ * @see device.accelerationY
776
+ * @see device.accelerationZ
777
+ * @link {http://www.mobilexweb.com/samples/ball.html}
778
+ * @link {http://www.mobilexweb.com/blog/safari-ios-accelerometer-websockets-html5}
779
+ * @returns {boolean} false if not supported or permission not granted by the user
780
+ * @example
781
+ * // try to enable device accelerometer event on user gesture
782
+ * me.input.registerPointerEvent("pointerleave", me.game.viewport, function() {
783
+ * if (me.device.watchAccelerometer() === true) {
784
+ * // Success
785
+ * me.input.releasePointerEvent("pointerleave", me.game.viewport);
786
+ * } else {
787
+ * // ... fail at enabling the device accelerometer event
788
+ * }
789
+ * });
1082
790
  */
1083
- Object.defineProperty(device, "devicePixelRatio", {
1084
- /**
1085
- * @ignore
1086
- */
1087
- get: function () {
1088
- return (globalThis.devicePixelRatio || 1);
791
+ export function watchAccelerometer() {
792
+ if (hasAccelerometer && !accelInitialized) {
793
+ if (DeviceOrientationEvent && typeof DeviceOrientationEvent.requestPermission === "function") {
794
+ DeviceOrientationEvent.requestPermission()
795
+ .then(response => {
796
+ if (response === "granted") {
797
+ // add a listener for the devicemotion event
798
+ globalThis.addEventListener("devicemotion", onDeviceMotion, false);
799
+ accelInitialized = true;
800
+ }
801
+ }).catch(console.error);
802
+ } else {
803
+ // add a listener for the devicemotion event
804
+ globalThis.addEventListener("devicemotion", onDeviceMotion, false);
805
+ accelInitialized = true;
806
+ }
1089
807
  }
1090
- });
808
+ return accelInitialized;
809
+ };
1091
810
 
1092
811
  /**
1093
- * Returns true if the browser/device is in full screen mode.
1094
- * @name device.isFullscreen
812
+ * unwatch Accelerometor event
813
+ * @function unwatchAccelerometer
814
+ * @memberof device
1095
815
  * @public
1096
- * @member {boolean}
1097
- * @readonly
1098
- * @returns {boolean}
1099
816
  */
1100
- Object.defineProperty(device, "isFullscreen", {
1101
- /**
1102
- * @ignore
1103
- */
1104
- get: function () {
1105
- if (this.hasFullscreenSupport) {
1106
- return !!(prefixed("fullscreenElement", document) ||
1107
- document.mozFullScreenElement);
817
+ export function unwatchAccelerometer() {
818
+ if (accelInitialized) {
819
+ // remove the listener for the devicemotion event
820
+ globalThis.removeEventListener("devicemotion", onDeviceMotion, false);
821
+ accelInitialized = false;
822
+ }
823
+ };
824
+
825
+ /**
826
+ * Enable monitor of the device orientation to detect the current orientation of the device as compared to the Earth coordinate frame.
827
+ * (one some device a first user gesture will be required before calling this function)
828
+ * @function watchDeviceOrientation
829
+ * @memberof device
830
+ * @public
831
+ * @see device.alpha
832
+ * @see device.beta
833
+ * @see device.gamma
834
+ * @returns {boolean} false if not supported or permission not granted by the user
835
+ * @example
836
+ * // try to enable device orientation event on user gesture
837
+ * me.input.registerPointerEvent("pointerleave", me.game.viewport, function() {
838
+ * if (me.device.watchDeviceOrientation() === true) {
839
+ * // Success
840
+ * me.input.releasePointerEvent("pointerleave", me.game.viewport);
841
+ * } else {
842
+ * // ... fail at enabling the device orientation event
843
+ * }
844
+ * });
845
+ */
846
+ export function watchDeviceOrientation() {
847
+ if (hasDeviceOrientation && !deviceOrientationInitialized) {
848
+ if (typeof DeviceOrientationEvent.requestPermission === "function") {
849
+ DeviceOrientationEvent.requestPermission()
850
+ .then(response => {
851
+ if (response === "granted") {
852
+ globalThis.addEventListener("deviceorientation", onDeviceRotate, false);
853
+ deviceOrientationInitialized = true;
854
+ }
855
+ }).catch(console.error);
1108
856
  } else {
1109
- return false;
857
+ globalThis.addEventListener("deviceorientation", onDeviceRotate, false);
858
+ deviceOrientationInitialized = true;
1110
859
  }
1111
860
  }
1112
- });
861
+ return deviceOrientationInitialized;
862
+ };
1113
863
 
1114
864
  /**
1115
- * Returns true if the browser/device has audio capabilities.
1116
- * @name device.sound
865
+ * unwatch Device orientation event
866
+ * @function unwatchDeviceOrientation
867
+ * @memberof device
1117
868
  * @public
1118
- * @member {boolean}
1119
- * @readonly
1120
- * @returns {boolean}
1121
869
  */
1122
- Object.defineProperty(device, "sound", {
1123
- /**
1124
- * @ignore
1125
- */
1126
- get: function () {
1127
- return hasAudio();
870
+ export function unwatchDeviceOrientation() {
871
+ if (deviceOrientationInitialized) {
872
+ globalThis.removeEventListener("deviceorientation", onDeviceRotate, false);
873
+ deviceOrientationInitialized = false;
1128
874
  }
1129
- });
875
+ };
1130
876
 
1131
- export default device;
877
+ /**
878
+ * the vibrate method pulses the vibration hardware on the device, <br>
879
+ * If the device doesn't support vibration, this method has no effect. <br>
880
+ * If a vibration pattern is already in progress when this method is called,
881
+ * the previous pattern is halted and the new one begins instead.
882
+ * @function vibrate
883
+ * @memberof device
884
+ * @public
885
+ * @param {number|number[]} pattern pattern of vibration and pause intervals
886
+ * @example
887
+ * // vibrate for 1000 ms
888
+ * me.device.vibrate(1000);
889
+ * // or alternatively
890
+ * me.device.vibrate([1000]);
891
+ * // vibrate for 50 ms, be still for 100 ms, and then vibrate for 150 ms:
892
+ * me.device.vibrate([50, 100, 150]);
893
+ * // cancel any existing vibrations
894
+ * me.device.vibrate(0);
895
+ */
896
+ export function vibrate(pattern) {
897
+ if (typeof globalThis.navigator !== "undefined" && typeof globalThis.navigator.vibrate === "function") {
898
+ globalThis.navigator.vibrate(pattern);
899
+ }
900
+ };