melonjs 12.0.0 → 13.1.1

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