123-lang 2.1.1 → 2.1.3

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.
@@ -0,0 +1,3331 @@
1
+ // WebView
2
+ (function () {
3
+ var eventHandlers = {};
4
+
5
+ var locationHash = '';
6
+ try {
7
+ locationHash = location.hash.toString();
8
+ } catch (e) {}
9
+
10
+ var initParams = urlParseHashParams(locationHash);
11
+ var storedParams = sessionStorageGet('initParams');
12
+ if (storedParams) {
13
+ for (var key in storedParams) {
14
+ if (typeof initParams[key] === 'undefined') {
15
+ initParams[key] = storedParams[key];
16
+ }
17
+ }
18
+ }
19
+ sessionStorageSet('initParams', initParams);
20
+
21
+ var isIframe = false, iFrameStyle;
22
+ try {
23
+ isIframe = (window.parent != null && window != window.parent);
24
+ if (isIframe) {
25
+ window.addEventListener('message', function (event) {
26
+ if (event.source !== window.parent) return;
27
+ try {
28
+ var dataParsed = JSON.parse(event.data);
29
+ } catch (e) {
30
+ return;
31
+ }
32
+ if (!dataParsed || !dataParsed.eventType) {
33
+ return;
34
+ }
35
+ if (dataParsed.eventType == 'set_custom_style') {
36
+ if (event.origin === 'https://web.telegram.org') {
37
+ iFrameStyle.innerHTML = dataParsed.eventData;
38
+ }
39
+ } else if (dataParsed.eventType == 'reload_iframe') {
40
+ try {
41
+ window.parent.postMessage(JSON.stringify({eventType: 'iframe_will_reload'}), '*');
42
+ } catch (e) {}
43
+ location.reload();
44
+ } else {
45
+ receiveEvent(dataParsed.eventType, dataParsed.eventData);
46
+ }
47
+ });
48
+ iFrameStyle = document.createElement('style');
49
+ document.head.appendChild(iFrameStyle);
50
+ try {
51
+ window.parent.postMessage(JSON.stringify({eventType: 'iframe_ready', eventData: {reload_supported: true}}), '*');
52
+ } catch (e) {}
53
+ }
54
+ } catch (e) {}
55
+
56
+ function urlSafeDecode(urlencoded) {
57
+ try {
58
+ urlencoded = urlencoded.replace(/\+/g, '%20');
59
+ return decodeURIComponent(urlencoded);
60
+ } catch (e) {
61
+ return urlencoded;
62
+ }
63
+ }
64
+
65
+ function urlParseHashParams(locationHash) {
66
+ locationHash = locationHash.replace(/^#/, '');
67
+ var params = {};
68
+ if (!locationHash.length) {
69
+ return params;
70
+ }
71
+ if (locationHash.indexOf('=') < 0 && locationHash.indexOf('?') < 0) {
72
+ params._path = urlSafeDecode(locationHash);
73
+ return params;
74
+ }
75
+ var qIndex = locationHash.indexOf('?');
76
+ if (qIndex >= 0) {
77
+ var pathParam = locationHash.substr(0, qIndex);
78
+ params._path = urlSafeDecode(pathParam);
79
+ locationHash = locationHash.substr(qIndex + 1);
80
+ }
81
+ var query_params = urlParseQueryString(locationHash);
82
+ for (var k in query_params) {
83
+ params[k] = query_params[k];
84
+ }
85
+ return params;
86
+ }
87
+
88
+ function urlParseQueryString(queryString) {
89
+ var params = {};
90
+ if (!queryString.length) {
91
+ return params;
92
+ }
93
+ var queryStringParams = queryString.split('&');
94
+ var i, param, paramName, paramValue;
95
+ for (i = 0; i < queryStringParams.length; i++) {
96
+ param = queryStringParams[i].split('=');
97
+ paramName = urlSafeDecode(param[0]);
98
+ paramValue = param[1] == null ? null : urlSafeDecode(param[1]);
99
+ params[paramName] = paramValue;
100
+ }
101
+ return params;
102
+ }
103
+
104
+ // Telegram apps will implement this logic to add service params (e.g. tgShareScoreUrl) to game URL
105
+ function urlAppendHashParams(url, addHash) {
106
+ // url looks like 'https://game.com/path?query=1#hash'
107
+ // addHash looks like 'tgShareScoreUrl=' + encodeURIComponent('tgb://share_game_score?hash=very_long_hash123')
108
+
109
+ var ind = url.indexOf('#');
110
+ if (ind < 0) {
111
+ // https://game.com/path -> https://game.com/path#tgShareScoreUrl=etc
112
+ return url + '#' + addHash;
113
+ }
114
+ var curHash = url.substr(ind + 1);
115
+ if (curHash.indexOf('=') >= 0 || curHash.indexOf('?') >= 0) {
116
+ // https://game.com/#hash=1 -> https://game.com/#hash=1&tgShareScoreUrl=etc
117
+ // https://game.com/#path?query -> https://game.com/#path?query&tgShareScoreUrl=etc
118
+ return url + '&' + addHash;
119
+ }
120
+ // https://game.com/#hash -> https://game.com/#hash?tgShareScoreUrl=etc
121
+ if (curHash.length > 0) {
122
+ return url + '?' + addHash;
123
+ }
124
+ // https://game.com/# -> https://game.com/#tgShareScoreUrl=etc
125
+ return url + addHash;
126
+ }
127
+
128
+ function postEvent(eventType, callback, eventData) {
129
+ if (!callback) {
130
+ callback = function () {};
131
+ }
132
+ if (eventData === undefined) {
133
+ eventData = '';
134
+ }
135
+ console.log('[Telegram.WebView] > postEvent', eventType, eventData);
136
+
137
+ if (window.TelegramWebviewProxy !== undefined) {
138
+ TelegramWebviewProxy.postEvent(eventType, JSON.stringify(eventData));
139
+ callback();
140
+ }
141
+ else if (window.external && 'notify' in window.external) {
142
+ window.external.notify(JSON.stringify({eventType: eventType, eventData: eventData}));
143
+ callback();
144
+ }
145
+ else if (isIframe) {
146
+ try {
147
+ var trustedTarget = 'https://web.telegram.org';
148
+ // For now we don't restrict target, for testing purposes
149
+ trustedTarget = '*';
150
+ window.parent.postMessage(JSON.stringify({eventType: eventType, eventData: eventData}), trustedTarget);
151
+ callback();
152
+ } catch (e) {
153
+ callback(e);
154
+ }
155
+ }
156
+ else {
157
+ callback({notAvailable: true});
158
+ }
159
+ };
160
+
161
+ function receiveEvent(eventType, eventData) {
162
+ console.log('[Telegram.WebView] < receiveEvent', eventType, eventData);
163
+ callEventCallbacks(eventType, function(callback) {
164
+ callback(eventType, eventData);
165
+ });
166
+ }
167
+
168
+ function callEventCallbacks(eventType, func) {
169
+ var curEventHandlers = eventHandlers[eventType];
170
+ if (curEventHandlers === undefined ||
171
+ !curEventHandlers.length) {
172
+ return;
173
+ }
174
+ for (var i = 0; i < curEventHandlers.length; i++) {
175
+ try {
176
+ func(curEventHandlers[i]);
177
+ } catch (e) {}
178
+ }
179
+ }
180
+
181
+ function onEvent(eventType, callback) {
182
+ if (eventHandlers[eventType] === undefined) {
183
+ eventHandlers[eventType] = [];
184
+ }
185
+ var index = eventHandlers[eventType].indexOf(callback);
186
+ if (index === -1) {
187
+ eventHandlers[eventType].push(callback);
188
+ }
189
+ };
190
+
191
+ function offEvent(eventType, callback) {
192
+ if (eventHandlers[eventType] === undefined) {
193
+ return;
194
+ }
195
+ var index = eventHandlers[eventType].indexOf(callback);
196
+ if (index === -1) {
197
+ return;
198
+ }
199
+ eventHandlers[eventType].splice(index, 1);
200
+ };
201
+
202
+ function openProtoUrl(url) {
203
+ if (!url.match(/^(web\+)?tgb?:\/\/./)) {
204
+ return false;
205
+ }
206
+ var useIframe = navigator.userAgent.match(/iOS|iPhone OS|iPhone|iPod|iPad/i) ? true : false;
207
+ if (useIframe) {
208
+ var iframeContEl = document.getElementById('tgme_frame_cont') || document.body;
209
+ var iframeEl = document.createElement('iframe');
210
+ iframeContEl.appendChild(iframeEl);
211
+ var pageHidden = false;
212
+ var enableHidden = function () {
213
+ pageHidden = true;
214
+ };
215
+ window.addEventListener('pagehide', enableHidden, false);
216
+ window.addEventListener('blur', enableHidden, false);
217
+ if (iframeEl !== null) {
218
+ iframeEl.src = url;
219
+ }
220
+ setTimeout(function() {
221
+ if (!pageHidden) {
222
+ window.location = url;
223
+ }
224
+ window.removeEventListener('pagehide', enableHidden, false);
225
+ window.removeEventListener('blur', enableHidden, false);
226
+ }, 2000);
227
+ }
228
+ else {
229
+ window.location = url;
230
+ }
231
+ return true;
232
+ }
233
+
234
+ function sessionStorageSet(key, value) {
235
+ try {
236
+ window.sessionStorage.setItem('__telegram__' + key, JSON.stringify(value));
237
+ return true;
238
+ } catch(e) {}
239
+ return false;
240
+ }
241
+ function sessionStorageGet(key) {
242
+ try {
243
+ return JSON.parse(window.sessionStorage.getItem('__telegram__' + key));
244
+ } catch(e) {}
245
+ return null;
246
+ }
247
+
248
+ if (!window.Telegram) {
249
+ window.Telegram = {};
250
+ }
251
+ window.Telegram.WebView = {
252
+ initParams: initParams,
253
+ isIframe: isIframe,
254
+ onEvent: onEvent,
255
+ offEvent: offEvent,
256
+ postEvent: postEvent,
257
+ receiveEvent: receiveEvent,
258
+ callEventCallbacks: callEventCallbacks
259
+ };
260
+
261
+ window.Telegram.Utils = {
262
+ urlSafeDecode: urlSafeDecode,
263
+ urlParseQueryString: urlParseQueryString,
264
+ urlParseHashParams: urlParseHashParams,
265
+ urlAppendHashParams: urlAppendHashParams,
266
+ sessionStorageSet: sessionStorageSet,
267
+ sessionStorageGet: sessionStorageGet
268
+ };
269
+
270
+ // For Windows Phone app
271
+ window.TelegramGameProxy_receiveEvent = receiveEvent;
272
+
273
+ // App backward compatibility
274
+ window.TelegramGameProxy = {
275
+ receiveEvent: receiveEvent
276
+ };
277
+ })();
278
+
279
+ // WebApp
280
+ (function () {
281
+ var Utils = window.Telegram.Utils;
282
+ var WebView = window.Telegram.WebView;
283
+ var initParams = WebView.initParams;
284
+ var isIframe = WebView.isIframe;
285
+
286
+ var WebApp = {};
287
+ var webAppInitData = '', webAppInitDataUnsafe = {};
288
+ var themeParams = {}, colorScheme = 'light';
289
+ var webAppVersion = '6.0';
290
+ var webAppPlatform = 'unknown';
291
+ var webAppIsActive = true;
292
+ var webAppIsFullscreen = false;
293
+ var webAppIsOrientationLocked = false;
294
+ var webAppBackgroundColor = 'bg_color';
295
+ var webAppHeaderColorKey = 'bg_color';
296
+ var webAppHeaderColor = null;
297
+
298
+ if (initParams.tgWebAppData && initParams.tgWebAppData.length) {
299
+ webAppInitData = initParams.tgWebAppData;
300
+ webAppInitDataUnsafe = Utils.urlParseQueryString(webAppInitData);
301
+ for (var key in webAppInitDataUnsafe) {
302
+ var val = webAppInitDataUnsafe[key];
303
+ try {
304
+ if (val.substr(0, 1) == '{' && val.substr(-1) == '}' ||
305
+ val.substr(0, 1) == '[' && val.substr(-1) == ']') {
306
+ webAppInitDataUnsafe[key] = JSON.parse(val);
307
+ }
308
+ } catch (e) {}
309
+ }
310
+ }
311
+ var stored_theme_params = Utils.sessionStorageGet('themeParams');
312
+ if (initParams.tgWebAppThemeParams && initParams.tgWebAppThemeParams.length) {
313
+ var themeParamsRaw = initParams.tgWebAppThemeParams;
314
+ try {
315
+ var theme_params = JSON.parse(themeParamsRaw);
316
+ if (theme_params) {
317
+ setThemeParams(theme_params);
318
+ }
319
+ } catch (e) {}
320
+ }
321
+ if (stored_theme_params) {
322
+ setThemeParams(stored_theme_params);
323
+ }
324
+ var stored_def_colors = Utils.sessionStorageGet('defaultColors');
325
+ if (initParams.tgWebAppDefaultColors && initParams.tgWebAppDefaultColors.length) {
326
+ var defColorsRaw = initParams.tgWebAppDefaultColors;
327
+ try {
328
+ var def_colors = JSON.parse(defColorsRaw);
329
+ if (def_colors) {
330
+ setDefaultColors(def_colors);
331
+ }
332
+ } catch (e) {}
333
+ }
334
+ if (stored_def_colors) {
335
+ setDefaultColors(stored_def_colors);
336
+ }
337
+ if (initParams.tgWebAppVersion) {
338
+ webAppVersion = initParams.tgWebAppVersion;
339
+ }
340
+ if (initParams.tgWebAppPlatform) {
341
+ webAppPlatform = initParams.tgWebAppPlatform;
342
+ }
343
+
344
+ var stored_fullscreen = Utils.sessionStorageGet('isFullscreen');
345
+ if (initParams.tgWebAppFullscreen) {
346
+ setFullscreen(true);
347
+ }
348
+ if (stored_fullscreen) {
349
+ setFullscreen(stored_fullscreen == 'yes');
350
+ }
351
+
352
+ var stored_orientation_lock = Utils.sessionStorageGet('isOrientationLocked');
353
+ if (stored_orientation_lock) {
354
+ setOrientationLock(stored_orientation_lock == 'yes');
355
+ }
356
+
357
+ function onThemeChanged(eventType, eventData) {
358
+ if (eventData.theme_params) {
359
+ setThemeParams(eventData.theme_params);
360
+ window.Telegram.WebApp.MainButton.setParams({});
361
+ window.Telegram.WebApp.SecondaryButton.setParams({});
362
+ updateHeaderColor();
363
+ updateBackgroundColor();
364
+ updateBottomBarColor();
365
+ receiveWebViewEvent('themeChanged');
366
+ }
367
+ }
368
+
369
+ var lastWindowHeight = window.innerHeight;
370
+ function onViewportChanged(eventType, eventData) {
371
+ if (eventData.height) {
372
+ window.removeEventListener('resize', onWindowResize);
373
+ setViewportHeight(eventData);
374
+ }
375
+ }
376
+
377
+ function onWindowResize(e) {
378
+ if (lastWindowHeight != window.innerHeight) {
379
+ lastWindowHeight = window.innerHeight;
380
+ receiveWebViewEvent('viewportChanged', {
381
+ isStateStable: true
382
+ });
383
+ }
384
+ }
385
+
386
+ function onSafeAreaChanged(eventType, eventData) {
387
+ if (eventData) {
388
+ setSafeAreaInset(eventData);
389
+ }
390
+ }
391
+ function onContentSafeAreaChanged(eventType, eventData) {
392
+ if (eventData) {
393
+ setContentSafeAreaInset(eventData);
394
+ }
395
+ }
396
+
397
+ function onVisibilityChanged(eventType, eventData) {
398
+ if (eventData.is_visible) {
399
+ webAppIsActive = true;
400
+ receiveWebViewEvent('activated');
401
+ } else {
402
+ webAppIsActive = false;
403
+ receiveWebViewEvent('deactivated');
404
+ }
405
+ }
406
+
407
+ function linkHandler(e) {
408
+ if (e.metaKey || e.ctrlKey) return;
409
+ var el = e.target;
410
+ while (el.tagName != 'A' && el.parentNode) {
411
+ el = el.parentNode;
412
+ }
413
+ if (el.tagName == 'A' &&
414
+ el.target != '_blank' &&
415
+ (el.protocol == 'http:' || el.protocol == 'https:') &&
416
+ el.hostname == 't.me') {
417
+ WebApp.openTelegramLink(el.href);
418
+ e.preventDefault();
419
+ }
420
+ }
421
+
422
+ function strTrim(str) {
423
+ return str.toString().replace(/^\s+|\s+$/g, '');
424
+ }
425
+
426
+ function receiveWebViewEvent(eventType) {
427
+ var args = Array.prototype.slice.call(arguments);
428
+ eventType = args.shift();
429
+ WebView.callEventCallbacks('webview:' + eventType, function(callback) {
430
+ callback.apply(WebApp, args);
431
+ });
432
+ }
433
+
434
+ function onWebViewEvent(eventType, callback) {
435
+ WebView.onEvent('webview:' + eventType, callback);
436
+ };
437
+
438
+ function offWebViewEvent(eventType, callback) {
439
+ WebView.offEvent('webview:' + eventType, callback);
440
+ };
441
+
442
+ function setCssProperty(name, value) {
443
+ var root = document.documentElement;
444
+ if (root && root.style && root.style.setProperty) {
445
+ root.style.setProperty('--tg-' + name, value);
446
+ }
447
+ }
448
+
449
+ function setFullscreen(is_fullscreen) {
450
+ webAppIsFullscreen = !!is_fullscreen;
451
+ Utils.sessionStorageSet('isFullscreen', webAppIsFullscreen ? 'yes' : 'no');
452
+ }
453
+
454
+ function setOrientationLock(is_locked) {
455
+ webAppIsOrientationLocked = !!is_locked;
456
+ Utils.sessionStorageSet('isOrientationLocked', webAppIsOrientationLocked ? 'yes' : 'no');
457
+ }
458
+
459
+ function setThemeParams(theme_params) {
460
+ // temp iOS fix
461
+ if (theme_params.bg_color == '#1c1c1d' &&
462
+ theme_params.bg_color == theme_params.secondary_bg_color) {
463
+ theme_params.secondary_bg_color = '#2c2c2e';
464
+ }
465
+ var color;
466
+ for (var key in theme_params) {
467
+ if (color = parseColorToHex(theme_params[key])) {
468
+ themeParams[key] = color;
469
+ if (key == 'bg_color') {
470
+ colorScheme = isColorDark(color) ? 'dark' : 'light'
471
+ setCssProperty('color-scheme', colorScheme);
472
+ }
473
+ key = 'theme-' + key.split('_').join('-');
474
+ setCssProperty(key, color);
475
+ }
476
+ }
477
+ Utils.sessionStorageSet('themeParams', themeParams);
478
+ }
479
+
480
+ function setDefaultColors(def_colors) {
481
+ if (colorScheme == 'dark') {
482
+ if (def_colors.bg_dark_color) {
483
+ webAppBackgroundColor = def_colors.bg_dark_color;
484
+ }
485
+ if (def_colors.header_dark_color) {
486
+ webAppHeaderColorKey = null;
487
+ webAppHeaderColor = def_colors.header_dark_color;
488
+ }
489
+ } else {
490
+ if (def_colors.bg_color) {
491
+ webAppBackgroundColor = def_colors.bg_color;
492
+ }
493
+ if (def_colors.header_color) {
494
+ webAppHeaderColorKey = null;
495
+ webAppHeaderColor = def_colors.header_color;
496
+ }
497
+ }
498
+ Utils.sessionStorageSet('defaultColors', def_colors);
499
+ }
500
+
501
+ var webAppCallbacks = {};
502
+ function generateCallbackId(len) {
503
+ var tries = 100;
504
+ while (--tries) {
505
+ var id = '', chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', chars_len = chars.length;
506
+ for (var i = 0; i < len; i++) {
507
+ id += chars[Math.floor(Math.random() * chars_len)];
508
+ }
509
+ if (!webAppCallbacks[id]) {
510
+ webAppCallbacks[id] = {};
511
+ return id;
512
+ }
513
+ }
514
+ throw Error('WebAppCallbackIdGenerateFailed');
515
+ }
516
+
517
+ var viewportHeight = false, viewportStableHeight = false, isExpanded = true;
518
+ function setViewportHeight(data) {
519
+ if (typeof data !== 'undefined') {
520
+ isExpanded = !!data.is_expanded;
521
+ viewportHeight = data.height;
522
+ if (data.is_state_stable) {
523
+ viewportStableHeight = data.height;
524
+ }
525
+ receiveWebViewEvent('viewportChanged', {
526
+ isStateStable: !!data.is_state_stable
527
+ });
528
+ }
529
+ var height, stable_height;
530
+ if (viewportHeight !== false) {
531
+ height = (viewportHeight - bottomBarHeight) + 'px';
532
+ } else {
533
+ height = bottomBarHeight ? 'calc(100vh - ' + bottomBarHeight + 'px)' : '100vh';
534
+ }
535
+ if (viewportStableHeight !== false) {
536
+ stable_height = (viewportStableHeight - bottomBarHeight) + 'px';
537
+ } else {
538
+ stable_height = bottomBarHeight ? 'calc(100vh - ' + bottomBarHeight + 'px)' : '100vh';
539
+ }
540
+ setCssProperty('viewport-height', height);
541
+ setCssProperty('viewport-stable-height', stable_height);
542
+ }
543
+
544
+ var safeAreaInset = {top: 0, bottom: 0, left: 0, right: 0};
545
+ function setSafeAreaInset(data) {
546
+ if (typeof data !== 'undefined') {
547
+ if (typeof data.top !== 'undefined') {
548
+ safeAreaInset.top = data.top;
549
+ }
550
+ if (typeof data.bottom !== 'undefined') {
551
+ safeAreaInset.bottom = data.bottom;
552
+ }
553
+ if (typeof data.left !== 'undefined') {
554
+ safeAreaInset.left = data.left;
555
+ }
556
+ if (typeof data.right !== 'undefined') {
557
+ safeAreaInset.right = data.right;
558
+ }
559
+ receiveWebViewEvent('safeAreaChanged');
560
+ }
561
+ setCssProperty('safe-area-inset-top', safeAreaInset.top + 'px');
562
+ setCssProperty('safe-area-inset-bottom', safeAreaInset.bottom + 'px');
563
+ setCssProperty('safe-area-inset-left', safeAreaInset.left + 'px');
564
+ setCssProperty('safe-area-inset-right', safeAreaInset.right + 'px');
565
+ }
566
+
567
+ var contentSafeAreaInset = {top: 0, bottom: 0, left: 0, right: 0};
568
+ function setContentSafeAreaInset(data) {
569
+ if (typeof data !== 'undefined') {
570
+ if (typeof data.top !== 'undefined') {
571
+ contentSafeAreaInset.top = data.top;
572
+ }
573
+ if (typeof data.bottom !== 'undefined') {
574
+ contentSafeAreaInset.bottom = data.bottom;
575
+ }
576
+ if (typeof data.left !== 'undefined') {
577
+ contentSafeAreaInset.left = data.left;
578
+ }
579
+ if (typeof data.right !== 'undefined') {
580
+ contentSafeAreaInset.right = data.right;
581
+ }
582
+ receiveWebViewEvent('contentSafeAreaChanged');
583
+ }
584
+ setCssProperty('content-safe-area-inset-top', contentSafeAreaInset.top + 'px');
585
+ setCssProperty('content-safe-area-inset-bottom', contentSafeAreaInset.bottom + 'px');
586
+ setCssProperty('content-safe-area-inset-left', contentSafeAreaInset.left + 'px');
587
+ setCssProperty('content-safe-area-inset-right', contentSafeAreaInset.right + 'px');
588
+ }
589
+
590
+ var isClosingConfirmationEnabled = false;
591
+ function setClosingConfirmation(need_confirmation) {
592
+ if (!versionAtLeast('6.2')) {
593
+ console.warn('[Telegram.WebApp] Closing confirmation is not supported in version ' + webAppVersion);
594
+ return;
595
+ }
596
+ isClosingConfirmationEnabled = !!need_confirmation;
597
+ WebView.postEvent('web_app_setup_closing_behavior', false, {need_confirmation: isClosingConfirmationEnabled});
598
+ }
599
+
600
+ var isVerticalSwipesEnabled = true;
601
+ function toggleVerticalSwipes(enable_swipes) {
602
+ if (!versionAtLeast('7.7')) {
603
+ console.warn('[Telegram.WebApp] Changing swipes behavior is not supported in version ' + webAppVersion);
604
+ return;
605
+ }
606
+ isVerticalSwipesEnabled = !!enable_swipes;
607
+ WebView.postEvent('web_app_setup_swipe_behavior', false, {allow_vertical_swipe: isVerticalSwipesEnabled});
608
+ }
609
+
610
+ function onFullscreenChanged(eventType, eventData) {
611
+ setFullscreen(eventData.is_fullscreen);
612
+ receiveWebViewEvent('fullscreenChanged');
613
+ }
614
+ function onFullscreenFailed(eventType, eventData) {
615
+ if (eventData.error == 'ALREADY_FULLSCREEN' && !webAppIsFullscreen) {
616
+ setFullscreen(true);
617
+ }
618
+ receiveWebViewEvent('fullscreenFailed', {
619
+ error: eventData.error
620
+ });
621
+ }
622
+
623
+ function toggleOrientationLock(locked) {
624
+ if (!versionAtLeast('8.0')) {
625
+ console.warn('[Telegram.WebApp] Orientation locking is not supported in version ' + webAppVersion);
626
+ return;
627
+ }
628
+ setOrientationLock(locked);
629
+ WebView.postEvent('web_app_toggle_orientation_lock', false, {locked: webAppIsOrientationLocked});
630
+ }
631
+
632
+ var homeScreenCallbacks = [];
633
+ function onHomeScreenAdded(eventType, eventData) {
634
+ receiveWebViewEvent('homeScreenAdded');
635
+ }
636
+ function onHomeScreenChecked(eventType, eventData) {
637
+ var status = eventData.status || 'unknown';
638
+ if (homeScreenCallbacks.length > 0) {
639
+ for (var i = 0; i < homeScreenCallbacks.length; i++) {
640
+ var callback = homeScreenCallbacks[i];
641
+ callback(status);
642
+ }
643
+ homeScreenCallbacks = [];
644
+ }
645
+ receiveWebViewEvent('homeScreenChecked', {
646
+ status: status
647
+ });
648
+ }
649
+
650
+ var WebAppShareMessageOpened = false;
651
+ function onPreparedMessageSent(eventType, eventData) {
652
+ if (WebAppShareMessageOpened) {
653
+ var requestData = WebAppShareMessageOpened;
654
+ WebAppShareMessageOpened = false;
655
+ if (requestData.callback) {
656
+ requestData.callback(true);
657
+ }
658
+ receiveWebViewEvent('shareMessageSent');
659
+ }
660
+ }
661
+ function onPreparedMessageFailed(eventType, eventData) {
662
+ if (WebAppShareMessageOpened) {
663
+ var requestData = WebAppShareMessageOpened;
664
+ WebAppShareMessageOpened = false;
665
+ if (requestData.callback) {
666
+ requestData.callback(false);
667
+ }
668
+ receiveWebViewEvent('shareMessageFailed', {
669
+ error: eventData.error
670
+ });
671
+ }
672
+ }
673
+
674
+ var WebAppEmojiStatusRequested = false;
675
+ function onEmojiStatusSet(eventType, eventData) {
676
+ if (WebAppEmojiStatusRequested) {
677
+ var requestData = WebAppEmojiStatusRequested;
678
+ WebAppEmojiStatusRequested = false;
679
+ if (requestData.callback) {
680
+ requestData.callback(true);
681
+ }
682
+ receiveWebViewEvent('emojiStatusSet');
683
+ }
684
+ }
685
+ function onEmojiStatusFailed(eventType, eventData) {
686
+ if (WebAppEmojiStatusRequested) {
687
+ var requestData = WebAppEmojiStatusRequested;
688
+ WebAppEmojiStatusRequested = false;
689
+ if (requestData.callback) {
690
+ requestData.callback(false);
691
+ }
692
+ receiveWebViewEvent('emojiStatusFailed', {
693
+ error: eventData.error
694
+ });
695
+ }
696
+ }
697
+ var WebAppEmojiStatusAccessRequested = false;
698
+ function onEmojiStatusAccessRequested(eventType, eventData) {
699
+ if (WebAppEmojiStatusAccessRequested) {
700
+ var requestData = WebAppEmojiStatusAccessRequested;
701
+ WebAppEmojiStatusAccessRequested = false;
702
+ if (requestData.callback) {
703
+ requestData.callback(eventData.status == 'allowed');
704
+ }
705
+ receiveWebViewEvent('emojiStatusAccessRequested', {
706
+ status: eventData.status
707
+ });
708
+ }
709
+ }
710
+
711
+ var webAppPopupOpened = false;
712
+ function onPopupClosed(eventType, eventData) {
713
+ if (webAppPopupOpened) {
714
+ var popupData = webAppPopupOpened;
715
+ webAppPopupOpened = false;
716
+ var button_id = null;
717
+ if (typeof eventData.button_id !== 'undefined') {
718
+ button_id = eventData.button_id;
719
+ }
720
+ if (popupData.callback) {
721
+ popupData.callback(button_id);
722
+ }
723
+ receiveWebViewEvent('popupClosed', {
724
+ button_id: button_id
725
+ });
726
+ }
727
+ }
728
+
729
+
730
+ function getHeaderColor() {
731
+ if (webAppHeaderColorKey == 'secondary_bg_color') {
732
+ return themeParams.secondary_bg_color;
733
+ } else if (webAppHeaderColorKey == 'bg_color') {
734
+ return themeParams.bg_color;
735
+ }
736
+ return webAppHeaderColor;
737
+ }
738
+ function setHeaderColor(color) {
739
+ if (!versionAtLeast('6.1')) {
740
+ console.warn('[Telegram.WebApp] Header color is not supported in version ' + webAppVersion);
741
+ return;
742
+ }
743
+ if (!versionAtLeast('6.9')) {
744
+ if (themeParams.bg_color &&
745
+ themeParams.bg_color == color) {
746
+ color = 'bg_color';
747
+ } else if (themeParams.secondary_bg_color &&
748
+ themeParams.secondary_bg_color == color) {
749
+ color = 'secondary_bg_color';
750
+ }
751
+ }
752
+ var head_color = null, color_key = null;
753
+ if (color == 'bg_color' || color == 'secondary_bg_color') {
754
+ color_key = color;
755
+ } else if (versionAtLeast('6.9')) {
756
+ head_color = parseColorToHex(color);
757
+ if (!head_color) {
758
+ console.error('[Telegram.WebApp] Header color format is invalid', color);
759
+ throw Error('WebAppHeaderColorInvalid');
760
+ }
761
+ }
762
+ if (!versionAtLeast('6.9') &&
763
+ color_key != 'bg_color' &&
764
+ color_key != 'secondary_bg_color') {
765
+ console.error('[Telegram.WebApp] Header color key should be one of Telegram.WebApp.themeParams.bg_color, Telegram.WebApp.themeParams.secondary_bg_color, \'bg_color\', \'secondary_bg_color\'', color);
766
+ throw Error('WebAppHeaderColorKeyInvalid');
767
+ }
768
+ webAppHeaderColorKey = color_key;
769
+ webAppHeaderColor = head_color;
770
+ updateHeaderColor();
771
+ }
772
+ var appHeaderColorKey = null, appHeaderColor = null;
773
+ function updateHeaderColor() {
774
+ if (appHeaderColorKey != webAppHeaderColorKey ||
775
+ appHeaderColor != webAppHeaderColor) {
776
+ appHeaderColorKey = webAppHeaderColorKey;
777
+ appHeaderColor = webAppHeaderColor;
778
+ if (appHeaderColor) {
779
+ WebView.postEvent('web_app_set_header_color', false, {color: webAppHeaderColor});
780
+ } else {
781
+ WebView.postEvent('web_app_set_header_color', false, {color_key: webAppHeaderColorKey});
782
+ }
783
+ }
784
+ }
785
+
786
+ function getBackgroundColor() {
787
+ if (webAppBackgroundColor == 'secondary_bg_color') {
788
+ return themeParams.secondary_bg_color;
789
+ } else if (webAppBackgroundColor == 'bg_color') {
790
+ return themeParams.bg_color;
791
+ }
792
+ return webAppBackgroundColor;
793
+ }
794
+ function setBackgroundColor(color) {
795
+ if (!versionAtLeast('6.1')) {
796
+ console.warn('[Telegram.WebApp] Background color is not supported in version ' + webAppVersion);
797
+ return;
798
+ }
799
+ var bg_color;
800
+ if (color == 'bg_color' || color == 'secondary_bg_color') {
801
+ bg_color = color;
802
+ } else {
803
+ bg_color = parseColorToHex(color);
804
+ if (!bg_color) {
805
+ console.error('[Telegram.WebApp] Background color format is invalid', color);
806
+ throw Error('WebAppBackgroundColorInvalid');
807
+ }
808
+ }
809
+ webAppBackgroundColor = bg_color;
810
+ updateBackgroundColor();
811
+ }
812
+ var appBackgroundColor = null;
813
+ function updateBackgroundColor() {
814
+ var color = getBackgroundColor();
815
+ if (appBackgroundColor != color) {
816
+ appBackgroundColor = color;
817
+ WebView.postEvent('web_app_set_background_color', false, {color: color});
818
+ }
819
+ }
820
+
821
+ var bottomBarColor = 'bottom_bar_bg_color';
822
+ function getBottomBarColor() {
823
+ if (bottomBarColor == 'bottom_bar_bg_color') {
824
+ return themeParams.bottom_bar_bg_color || themeParams.secondary_bg_color || '#ffffff';
825
+ } else if (bottomBarColor == 'secondary_bg_color') {
826
+ return themeParams.secondary_bg_color;
827
+ } else if (bottomBarColor == 'bg_color') {
828
+ return themeParams.bg_color;
829
+ }
830
+ return bottomBarColor;
831
+ }
832
+ function setBottomBarColor(color) {
833
+ if (!versionAtLeast('7.10')) {
834
+ console.warn('[Telegram.WebApp] Bottom bar color is not supported in version ' + webAppVersion);
835
+ return;
836
+ }
837
+ var bg_color;
838
+ if (color == 'bg_color' || color == 'secondary_bg_color' || color == 'bottom_bar_bg_color') {
839
+ bg_color = color;
840
+ } else {
841
+ bg_color = parseColorToHex(color);
842
+ if (!bg_color) {
843
+ console.error('[Telegram.WebApp] Bottom bar color format is invalid', color);
844
+ throw Error('WebAppBottomBarColorInvalid');
845
+ }
846
+ }
847
+ bottomBarColor = bg_color;
848
+ updateBottomBarColor();
849
+ window.Telegram.WebApp.SecondaryButton.setParams({});
850
+ }
851
+ var appBottomBarColor = null;
852
+ function updateBottomBarColor() {
853
+ var color = getBottomBarColor();
854
+ if (appBottomBarColor != color) {
855
+ appBottomBarColor = color;
856
+ WebView.postEvent('web_app_set_bottom_bar_color', false, {color: color});
857
+ }
858
+ if (initParams.tgWebAppDebug) {
859
+ updateDebugBottomBar();
860
+ }
861
+ }
862
+
863
+
864
+ function parseColorToHex(color) {
865
+ color += '';
866
+ var match;
867
+ if (match = /^\s*#([0-9a-f]{6})\s*$/i.exec(color)) {
868
+ return '#' + match[1].toLowerCase();
869
+ }
870
+ else if (match = /^\s*#([0-9a-f])([0-9a-f])([0-9a-f])\s*$/i.exec(color)) {
871
+ return ('#' + match[1] + match[1] + match[2] + match[2] + match[3] + match[3]).toLowerCase();
872
+ }
873
+ else if (match = /^\s*rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)\s*$/.exec(color)) {
874
+ var r = parseInt(match[1]), g = parseInt(match[2]), b = parseInt(match[3]);
875
+ r = (r < 16 ? '0' : '') + r.toString(16);
876
+ g = (g < 16 ? '0' : '') + g.toString(16);
877
+ b = (b < 16 ? '0' : '') + b.toString(16);
878
+ return '#' + r + g + b;
879
+ }
880
+ return false;
881
+ }
882
+
883
+ function isColorDark(rgb) {
884
+ rgb = rgb.replace(/[\s#]/g, '');
885
+ if (rgb.length == 3) {
886
+ rgb = rgb[0] + rgb[0] + rgb[1] + rgb[1] + rgb[2] + rgb[2];
887
+ }
888
+ var r = parseInt(rgb.substr(0, 2), 16);
889
+ var g = parseInt(rgb.substr(2, 2), 16);
890
+ var b = parseInt(rgb.substr(4, 2), 16);
891
+ var hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));
892
+ return hsp < 120;
893
+ }
894
+
895
+ function versionCompare(v1, v2) {
896
+ if (typeof v1 !== 'string') v1 = '';
897
+ if (typeof v2 !== 'string') v2 = '';
898
+ v1 = v1.replace(/^\s+|\s+$/g, '').split('.');
899
+ v2 = v2.replace(/^\s+|\s+$/g, '').split('.');
900
+ var a = Math.max(v1.length, v2.length), i, p1, p2;
901
+ for (i = 0; i < a; i++) {
902
+ p1 = parseInt(v1[i]) || 0;
903
+ p2 = parseInt(v2[i]) || 0;
904
+ if (p1 == p2) continue;
905
+ if (p1 > p2) return 1;
906
+ return -1;
907
+ }
908
+ return 0;
909
+ }
910
+
911
+ function versionAtLeast(ver) {
912
+ return versionCompare(webAppVersion, ver) >= 0;
913
+ }
914
+
915
+ function byteLength(str) {
916
+ if (window.Blob) {
917
+ try { return new Blob([str]).size; } catch (e) {}
918
+ }
919
+ var s = str.length;
920
+ for (var i=str.length-1; i>=0; i--) {
921
+ var code = str.charCodeAt(i);
922
+ if (code > 0x7f && code <= 0x7ff) s++;
923
+ else if (code > 0x7ff && code <= 0xffff) s+=2;
924
+ if (code >= 0xdc00 && code <= 0xdfff) i--;
925
+ }
926
+ return s;
927
+ }
928
+
929
+ var BackButton = (function() {
930
+ var isVisible = false;
931
+
932
+ var backButton = {};
933
+ Object.defineProperty(backButton, 'isVisible', {
934
+ set: function(val){ setParams({is_visible: val}); },
935
+ get: function(){ return isVisible; },
936
+ enumerable: true
937
+ });
938
+
939
+ var curButtonState = null;
940
+
941
+ WebView.onEvent('back_button_pressed', onBackButtonPressed);
942
+
943
+ function onBackButtonPressed() {
944
+ receiveWebViewEvent('backButtonClicked');
945
+ }
946
+
947
+ function buttonParams() {
948
+ return {is_visible: isVisible};
949
+ }
950
+
951
+ function buttonState(btn_params) {
952
+ if (typeof btn_params === 'undefined') {
953
+ btn_params = buttonParams();
954
+ }
955
+ return JSON.stringify(btn_params);
956
+ }
957
+
958
+ function buttonCheckVersion() {
959
+ if (!versionAtLeast('6.1')) {
960
+ console.warn('[Telegram.WebApp] BackButton is not supported in version ' + webAppVersion);
961
+ return false;
962
+ }
963
+ return true;
964
+ }
965
+
966
+ function updateButton() {
967
+ var btn_params = buttonParams();
968
+ var btn_state = buttonState(btn_params);
969
+ if (curButtonState === btn_state) {
970
+ return;
971
+ }
972
+ curButtonState = btn_state;
973
+ WebView.postEvent('web_app_setup_back_button', false, btn_params);
974
+ }
975
+
976
+ function setParams(params) {
977
+ if (!buttonCheckVersion()) {
978
+ return backButton;
979
+ }
980
+ if (typeof params.is_visible !== 'undefined') {
981
+ isVisible = !!params.is_visible;
982
+ }
983
+ updateButton();
984
+ return backButton;
985
+ }
986
+
987
+ backButton.onClick = function(callback) {
988
+ if (buttonCheckVersion()) {
989
+ onWebViewEvent('backButtonClicked', callback);
990
+ }
991
+ return backButton;
992
+ };
993
+ backButton.offClick = function(callback) {
994
+ if (buttonCheckVersion()) {
995
+ offWebViewEvent('backButtonClicked', callback);
996
+ }
997
+ return backButton;
998
+ };
999
+ backButton.show = function() {
1000
+ return setParams({is_visible: true});
1001
+ };
1002
+ backButton.hide = function() {
1003
+ return setParams({is_visible: false});
1004
+ };
1005
+ return backButton;
1006
+ })();
1007
+
1008
+ var debugBottomBar = null, debugBottomBarBtns = {}, bottomBarHeight = 0;
1009
+ if (initParams.tgWebAppDebug) {
1010
+ debugBottomBar = document.createElement('tg-bottom-bar');
1011
+ var debugBottomBarStyle = {
1012
+ display: 'flex',
1013
+ gap: '7px',
1014
+ font: '600 14px/18px sans-serif',
1015
+ width: '100%',
1016
+ background: getBottomBarColor(),
1017
+ position: 'fixed',
1018
+ left: '0',
1019
+ right: '0',
1020
+ bottom: '0',
1021
+ margin: '0',
1022
+ padding: '7px',
1023
+ textAlign: 'center',
1024
+ boxSizing: 'border-box',
1025
+ zIndex: '10000'
1026
+ };
1027
+ for (var k in debugBottomBarStyle) {
1028
+ debugBottomBar.style[k] = debugBottomBarStyle[k];
1029
+ }
1030
+ document.addEventListener('DOMContentLoaded', function onDomLoaded(event) {
1031
+ document.removeEventListener('DOMContentLoaded', onDomLoaded);
1032
+ document.body.appendChild(debugBottomBar);
1033
+ });
1034
+ var animStyle = document.createElement('style');
1035
+ animStyle.innerHTML = 'tg-bottom-button.shine { position: relative; overflow: hidden; } tg-bottom-button.shine:before { content:""; position: absolute; top: 0; width: 100%; height: 100%; background: linear-gradient(120deg, transparent, rgba(255, 255, 255, .2), transparent); animation: tg-bottom-button-shine 5s ease-in-out infinite; } @-webkit-keyframes tg-bottom-button-shine { 0% {left: -100%;} 12%,100% {left: 100%}} @keyframes tg-bottom-button-shine { 0% {left: -100%;} 12%,100% {left: 100%}}';
1036
+ debugBottomBar.appendChild(animStyle);
1037
+ }
1038
+ function updateDebugBottomBar() {
1039
+ var mainBtn = debugBottomBarBtns.main._bottomButton;
1040
+ var secondaryBtn = debugBottomBarBtns.secondary._bottomButton;
1041
+ if (mainBtn.isVisible || secondaryBtn.isVisible) {
1042
+ debugBottomBar.style.display = 'flex';
1043
+ bottomBarHeight = 58;
1044
+ if (mainBtn.isVisible && secondaryBtn.isVisible) {
1045
+ if (secondaryBtn.position == 'top') {
1046
+ debugBottomBar.style.flexDirection = 'column-reverse';
1047
+ bottomBarHeight += 51;
1048
+ } else if (secondaryBtn.position == 'bottom') {
1049
+ debugBottomBar.style.flexDirection = 'column';
1050
+ bottomBarHeight += 51;
1051
+ } else if (secondaryBtn.position == 'left') {
1052
+ debugBottomBar.style.flexDirection = 'row-reverse';
1053
+ } else if (secondaryBtn.position == 'right') {
1054
+ debugBottomBar.style.flexDirection = 'row';
1055
+ }
1056
+ }
1057
+ } else {
1058
+ debugBottomBar.style.display = 'none';
1059
+ bottomBarHeight = 0;
1060
+ }
1061
+ debugBottomBar.style.background = getBottomBarColor();
1062
+ if (document.documentElement) {
1063
+ document.documentElement.style.boxSizing = 'border-box';
1064
+ document.documentElement.style.paddingBottom = bottomBarHeight + 'px';
1065
+ }
1066
+ setViewportHeight();
1067
+ }
1068
+
1069
+
1070
+ var BottomButtonConstructor = function(type) {
1071
+ var isMainButton = (type == 'main');
1072
+ if (isMainButton) {
1073
+ var setupFnName = 'web_app_setup_main_button';
1074
+ var tgEventName = 'main_button_pressed';
1075
+ var webViewEventName = 'mainButtonClicked';
1076
+ var buttonTextDefault = 'Continue';
1077
+ var buttonColorDefault = function(){ return themeParams.button_color || '#2481cc'; };
1078
+ var buttonTextColorDefault = function(){ return themeParams.button_text_color || '#ffffff'; };
1079
+ } else {
1080
+ var setupFnName = 'web_app_setup_secondary_button';
1081
+ var tgEventName = 'secondary_button_pressed';
1082
+ var webViewEventName = 'secondaryButtonClicked';
1083
+ var buttonTextDefault = 'Cancel';
1084
+ var buttonColorDefault = function(){ return getBottomBarColor(); };
1085
+ var buttonTextColorDefault = function(){ return themeParams.button_color || '#2481cc'; };
1086
+ }
1087
+
1088
+ var isVisible = false;
1089
+ var isActive = true;
1090
+ var hasShineEffect = false;
1091
+ var isProgressVisible = false;
1092
+ var buttonType = type;
1093
+ var buttonText = buttonTextDefault;
1094
+ var buttonColor = false;
1095
+ var buttonTextColor = false;
1096
+ var buttonPosition = 'left';
1097
+
1098
+ var bottomButton = {};
1099
+ Object.defineProperty(bottomButton, 'type', {
1100
+ get: function(){ return buttonType; },
1101
+ enumerable: true
1102
+ });
1103
+ Object.defineProperty(bottomButton, 'text', {
1104
+ set: function(val){ bottomButton.setParams({text: val}); },
1105
+ get: function(){ return buttonText; },
1106
+ enumerable: true
1107
+ });
1108
+ Object.defineProperty(bottomButton, 'color', {
1109
+ set: function(val){ bottomButton.setParams({color: val}); },
1110
+ get: function(){ return buttonColor || buttonColorDefault(); },
1111
+ enumerable: true
1112
+ });
1113
+ Object.defineProperty(bottomButton, 'textColor', {
1114
+ set: function(val){ bottomButton.setParams({text_color: val}); },
1115
+ get: function(){ return buttonTextColor || buttonTextColorDefault(); },
1116
+ enumerable: true
1117
+ });
1118
+ Object.defineProperty(bottomButton, 'isVisible', {
1119
+ set: function(val){ bottomButton.setParams({is_visible: val}); },
1120
+ get: function(){ return isVisible; },
1121
+ enumerable: true
1122
+ });
1123
+ Object.defineProperty(bottomButton, 'isProgressVisible', {
1124
+ get: function(){ return isProgressVisible; },
1125
+ enumerable: true
1126
+ });
1127
+ Object.defineProperty(bottomButton, 'isActive', {
1128
+ set: function(val){ bottomButton.setParams({is_active: val}); },
1129
+ get: function(){ return isActive; },
1130
+ enumerable: true
1131
+ });
1132
+ Object.defineProperty(bottomButton, 'hasShineEffect', {
1133
+ set: function(val){ bottomButton.setParams({has_shine_effect: val}); },
1134
+ get: function(){ return hasShineEffect; },
1135
+ enumerable: true
1136
+ });
1137
+ if (!isMainButton) {
1138
+ Object.defineProperty(bottomButton, 'position', {
1139
+ set: function(val){ bottomButton.setParams({position: val}); },
1140
+ get: function(){ return buttonPosition; },
1141
+ enumerable: true
1142
+ });
1143
+ }
1144
+
1145
+ var curButtonState = null;
1146
+
1147
+ WebView.onEvent(tgEventName, onBottomButtonPressed);
1148
+
1149
+ var debugBtn = null;
1150
+ if (initParams.tgWebAppDebug) {
1151
+ debugBtn = document.createElement('tg-bottom-button');
1152
+ var debugBtnStyle = {
1153
+ display: 'none',
1154
+ width: '100%',
1155
+ height: '44px',
1156
+ borderRadius: '0',
1157
+ background: 'no-repeat right center',
1158
+ padding: '13px 15px',
1159
+ textAlign: 'center',
1160
+ boxSizing: 'border-box'
1161
+ };
1162
+ for (var k in debugBtnStyle) {
1163
+ debugBtn.style[k] = debugBtnStyle[k];
1164
+ }
1165
+ debugBottomBar.appendChild(debugBtn);
1166
+ debugBtn.addEventListener('click', onBottomButtonPressed, false);
1167
+ debugBtn._bottomButton = bottomButton;
1168
+ debugBottomBarBtns[type] = debugBtn;
1169
+ }
1170
+
1171
+ function onBottomButtonPressed() {
1172
+ if (isActive) {
1173
+ receiveWebViewEvent(webViewEventName);
1174
+ }
1175
+ }
1176
+
1177
+ function buttonParams() {
1178
+ var color = bottomButton.color;
1179
+ var text_color = bottomButton.textColor;
1180
+ if (isVisible) {
1181
+ var params = {
1182
+ is_visible: true,
1183
+ is_active: isActive,
1184
+ is_progress_visible: isProgressVisible,
1185
+ text: buttonText,
1186
+ color: color,
1187
+ text_color: text_color,
1188
+ has_shine_effect: hasShineEffect && isActive && !isProgressVisible
1189
+ };
1190
+ if (!isMainButton) {
1191
+ params.position = buttonPosition;
1192
+ }
1193
+ } else {
1194
+ var params = {
1195
+ is_visible: false
1196
+ };
1197
+ }
1198
+ return params;
1199
+ }
1200
+
1201
+ function buttonState(btn_params) {
1202
+ if (typeof btn_params === 'undefined') {
1203
+ btn_params = buttonParams();
1204
+ }
1205
+ return JSON.stringify(btn_params);
1206
+ }
1207
+
1208
+ function updateButton() {
1209
+ var btn_params = buttonParams();
1210
+ var btn_state = buttonState(btn_params);
1211
+ if (curButtonState === btn_state) {
1212
+ return;
1213
+ }
1214
+ curButtonState = btn_state;
1215
+ WebView.postEvent(setupFnName, false, btn_params);
1216
+ if (initParams.tgWebAppDebug) {
1217
+ updateDebugButton(btn_params);
1218
+ }
1219
+ }
1220
+
1221
+ function updateDebugButton(btn_params) {
1222
+ if (btn_params.is_visible) {
1223
+ debugBtn.style.display = 'block';
1224
+
1225
+ debugBtn.style.opacity = btn_params.is_active ? '1' : '0.8';
1226
+ debugBtn.style.cursor = btn_params.is_active ? 'pointer' : 'auto';
1227
+ debugBtn.disabled = !btn_params.is_active;
1228
+ debugBtn.innerText = btn_params.text;
1229
+ debugBtn.className = btn_params.has_shine_effect ? 'shine' : '';
1230
+ debugBtn.style.backgroundImage = btn_params.is_progress_visible ? "url('data:image/svg+xml," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewport="0 0 48 48" width="48px" height="48px"><circle cx="50%" cy="50%" stroke="' + btn_params.text_color + '" stroke-width="2.25" stroke-linecap="round" fill="none" stroke-dashoffset="106" r="9" stroke-dasharray="56.52" rotate="-90"><animate attributeName="stroke-dashoffset" attributeType="XML" dur="360s" from="0" to="12500" repeatCount="indefinite"></animate><animateTransform attributeName="transform" attributeType="XML" type="rotate" dur="1s" from="-90 24 24" to="630 24 24" repeatCount="indefinite"></animateTransform></circle></svg>') + "')" : 'none';
1231
+ debugBtn.style.backgroundColor = btn_params.color;
1232
+ debugBtn.style.color = btn_params.text_color;
1233
+ } else {
1234
+ debugBtn.style.display = 'none';
1235
+ }
1236
+ updateDebugBottomBar();
1237
+ }
1238
+
1239
+ function setParams(params) {
1240
+ if (typeof params.text !== 'undefined') {
1241
+ var text = strTrim(params.text);
1242
+ if (!text.length) {
1243
+ console.error('[Telegram.WebApp] Bottom button text is required', params.text);
1244
+ throw Error('WebAppBottomButtonParamInvalid');
1245
+ }
1246
+ if (text.length > 64) {
1247
+ console.error('[Telegram.WebApp] Bottom button text is too long', text);
1248
+ throw Error('WebAppBottomButtonParamInvalid');
1249
+ }
1250
+ buttonText = text;
1251
+ }
1252
+ if (typeof params.color !== 'undefined') {
1253
+ if (params.color === false ||
1254
+ params.color === null) {
1255
+ buttonColor = false;
1256
+ } else {
1257
+ var color = parseColorToHex(params.color);
1258
+ if (!color) {
1259
+ console.error('[Telegram.WebApp] Bottom button color format is invalid', params.color);
1260
+ throw Error('WebAppBottomButtonParamInvalid');
1261
+ }
1262
+ buttonColor = color;
1263
+ }
1264
+ }
1265
+ if (typeof params.text_color !== 'undefined') {
1266
+ if (params.text_color === false ||
1267
+ params.text_color === null) {
1268
+ buttonTextColor = false;
1269
+ } else {
1270
+ var text_color = parseColorToHex(params.text_color);
1271
+ if (!text_color) {
1272
+ console.error('[Telegram.WebApp] Bottom button text color format is invalid', params.text_color);
1273
+ throw Error('WebAppBottomButtonParamInvalid');
1274
+ }
1275
+ buttonTextColor = text_color;
1276
+ }
1277
+ }
1278
+ if (typeof params.is_visible !== 'undefined') {
1279
+ if (params.is_visible &&
1280
+ !bottomButton.text.length) {
1281
+ console.error('[Telegram.WebApp] Bottom button text is required');
1282
+ throw Error('WebAppBottomButtonParamInvalid');
1283
+ }
1284
+ isVisible = !!params.is_visible;
1285
+ }
1286
+ if (typeof params.has_shine_effect !== 'undefined') {
1287
+ hasShineEffect = !!params.has_shine_effect;
1288
+ }
1289
+ if (!isMainButton && typeof params.position !== 'undefined') {
1290
+ if (params.position != 'left' && params.position != 'right' &&
1291
+ params.position != 'top' && params.position != 'bottom') {
1292
+ console.error('[Telegram.WebApp] Bottom button posiition is invalid', params.position);
1293
+ throw Error('WebAppBottomButtonParamInvalid');
1294
+ }
1295
+ buttonPosition = params.position;
1296
+ }
1297
+ if (typeof params.is_active !== 'undefined') {
1298
+ isActive = !!params.is_active;
1299
+ }
1300
+ updateButton();
1301
+ return bottomButton;
1302
+ }
1303
+
1304
+ bottomButton.setText = function(text) {
1305
+ return bottomButton.setParams({text: text});
1306
+ };
1307
+ bottomButton.onClick = function(callback) {
1308
+ onWebViewEvent(webViewEventName, callback);
1309
+ return bottomButton;
1310
+ };
1311
+ bottomButton.offClick = function(callback) {
1312
+ offWebViewEvent(webViewEventName, callback);
1313
+ return bottomButton;
1314
+ };
1315
+ bottomButton.show = function() {
1316
+ return bottomButton.setParams({is_visible: true});
1317
+ };
1318
+ bottomButton.hide = function() {
1319
+ return bottomButton.setParams({is_visible: false});
1320
+ };
1321
+ bottomButton.enable = function() {
1322
+ return bottomButton.setParams({is_active: true});
1323
+ };
1324
+ bottomButton.disable = function() {
1325
+ return bottomButton.setParams({is_active: false});
1326
+ };
1327
+ bottomButton.showProgress = function(leaveActive) {
1328
+ isActive = !!leaveActive;
1329
+ isProgressVisible = true;
1330
+ updateButton();
1331
+ return bottomButton;
1332
+ };
1333
+ bottomButton.hideProgress = function() {
1334
+ if (!bottomButton.isActive) {
1335
+ isActive = true;
1336
+ }
1337
+ isProgressVisible = false;
1338
+ updateButton();
1339
+ return bottomButton;
1340
+ }
1341
+ bottomButton.setParams = setParams;
1342
+ return bottomButton;
1343
+ };
1344
+ var MainButton = BottomButtonConstructor('main');
1345
+ var SecondaryButton = BottomButtonConstructor('secondary');
1346
+
1347
+ var SettingsButton = (function() {
1348
+ var isVisible = false;
1349
+
1350
+ var settingsButton = {};
1351
+ Object.defineProperty(settingsButton, 'isVisible', {
1352
+ set: function(val){ setParams({is_visible: val}); },
1353
+ get: function(){ return isVisible; },
1354
+ enumerable: true
1355
+ });
1356
+
1357
+ var curButtonState = null;
1358
+
1359
+ WebView.onEvent('settings_button_pressed', onSettingsButtonPressed);
1360
+
1361
+ function onSettingsButtonPressed() {
1362
+ receiveWebViewEvent('settingsButtonClicked');
1363
+ }
1364
+
1365
+ function buttonParams() {
1366
+ return {is_visible: isVisible};
1367
+ }
1368
+
1369
+ function buttonState(btn_params) {
1370
+ if (typeof btn_params === 'undefined') {
1371
+ btn_params = buttonParams();
1372
+ }
1373
+ return JSON.stringify(btn_params);
1374
+ }
1375
+
1376
+ function buttonCheckVersion() {
1377
+ if (!versionAtLeast('6.10')) {
1378
+ console.warn('[Telegram.WebApp] SettingsButton is not supported in version ' + webAppVersion);
1379
+ return false;
1380
+ }
1381
+ return true;
1382
+ }
1383
+
1384
+ function updateButton() {
1385
+ var btn_params = buttonParams();
1386
+ var btn_state = buttonState(btn_params);
1387
+ if (curButtonState === btn_state) {
1388
+ return;
1389
+ }
1390
+ curButtonState = btn_state;
1391
+ WebView.postEvent('web_app_setup_settings_button', false, btn_params);
1392
+ }
1393
+
1394
+ function setParams(params) {
1395
+ if (!buttonCheckVersion()) {
1396
+ return settingsButton;
1397
+ }
1398
+ if (typeof params.is_visible !== 'undefined') {
1399
+ isVisible = !!params.is_visible;
1400
+ }
1401
+ updateButton();
1402
+ return settingsButton;
1403
+ }
1404
+
1405
+ settingsButton.onClick = function(callback) {
1406
+ if (buttonCheckVersion()) {
1407
+ onWebViewEvent('settingsButtonClicked', callback);
1408
+ }
1409
+ return settingsButton;
1410
+ };
1411
+ settingsButton.offClick = function(callback) {
1412
+ if (buttonCheckVersion()) {
1413
+ offWebViewEvent('settingsButtonClicked', callback);
1414
+ }
1415
+ return settingsButton;
1416
+ };
1417
+ settingsButton.show = function() {
1418
+ return setParams({is_visible: true});
1419
+ };
1420
+ settingsButton.hide = function() {
1421
+ return setParams({is_visible: false});
1422
+ };
1423
+ return settingsButton;
1424
+ })();
1425
+
1426
+ var HapticFeedback = (function() {
1427
+ var hapticFeedback = {};
1428
+
1429
+ function triggerFeedback(params) {
1430
+ if (!versionAtLeast('6.1')) {
1431
+ console.warn('[Telegram.WebApp] HapticFeedback is not supported in version ' + webAppVersion);
1432
+ return hapticFeedback;
1433
+ }
1434
+ if (params.type == 'impact') {
1435
+ if (params.impact_style != 'light' &&
1436
+ params.impact_style != 'medium' &&
1437
+ params.impact_style != 'heavy' &&
1438
+ params.impact_style != 'rigid' &&
1439
+ params.impact_style != 'soft') {
1440
+ console.error('[Telegram.WebApp] Haptic impact style is invalid', params.impact_style);
1441
+ throw Error('WebAppHapticImpactStyleInvalid');
1442
+ }
1443
+ } else if (params.type == 'notification') {
1444
+ if (params.notification_type != 'error' &&
1445
+ params.notification_type != 'success' &&
1446
+ params.notification_type != 'warning') {
1447
+ console.error('[Telegram.WebApp] Haptic notification type is invalid', params.notification_type);
1448
+ throw Error('WebAppHapticNotificationTypeInvalid');
1449
+ }
1450
+ } else if (params.type == 'selection_change') {
1451
+ // no params needed
1452
+ } else {
1453
+ console.error('[Telegram.WebApp] Haptic feedback type is invalid', params.type);
1454
+ throw Error('WebAppHapticFeedbackTypeInvalid');
1455
+ }
1456
+ WebView.postEvent('web_app_trigger_haptic_feedback', false, params);
1457
+ return hapticFeedback;
1458
+ }
1459
+
1460
+ hapticFeedback.impactOccurred = function(style) {
1461
+ return triggerFeedback({type: 'impact', impact_style: style});
1462
+ };
1463
+ hapticFeedback.notificationOccurred = function(type) {
1464
+ return triggerFeedback({type: 'notification', notification_type: type});
1465
+ };
1466
+ hapticFeedback.selectionChanged = function() {
1467
+ return triggerFeedback({type: 'selection_change'});
1468
+ };
1469
+ return hapticFeedback;
1470
+ })();
1471
+
1472
+ var CloudStorage = (function() {
1473
+ var cloudStorage = {};
1474
+
1475
+ function invokeStorageMethod(method, params, callback) {
1476
+ if (!versionAtLeast('6.9')) {
1477
+ console.error('[Telegram.WebApp] CloudStorage is not supported in version ' + webAppVersion);
1478
+ throw Error('WebAppMethodUnsupported');
1479
+ }
1480
+ invokeCustomMethod(method, params, callback);
1481
+ return cloudStorage;
1482
+ }
1483
+
1484
+ cloudStorage.setItem = function(key, value, callback) {
1485
+ return invokeStorageMethod('saveStorageValue', {key: key, value: value}, callback);
1486
+ };
1487
+ cloudStorage.getItem = function(key, callback) {
1488
+ return cloudStorage.getItems([key], callback ? function(err, res) {
1489
+ if (err) callback(err);
1490
+ else callback(null, res[key]);
1491
+ } : null);
1492
+ };
1493
+ cloudStorage.getItems = function(keys, callback) {
1494
+ return invokeStorageMethod('getStorageValues', {keys: keys}, callback);
1495
+ };
1496
+ cloudStorage.removeItem = function(key, callback) {
1497
+ return cloudStorage.removeItems([key], callback);
1498
+ };
1499
+ cloudStorage.removeItems = function(keys, callback) {
1500
+ return invokeStorageMethod('deleteStorageValues', {keys: keys}, callback);
1501
+ };
1502
+ cloudStorage.getKeys = function(callback) {
1503
+ return invokeStorageMethod('getStorageKeys', {}, callback);
1504
+ };
1505
+ return cloudStorage;
1506
+ })();
1507
+
1508
+ var DeviceStorage = (function() {
1509
+ var deviceStorage = {};
1510
+
1511
+ WebView.onEvent('device_storage_key_saved', onDeviceStorageEvent);
1512
+ WebView.onEvent('device_storage_key_received', onDeviceStorageEvent);
1513
+ WebView.onEvent('device_storage_cleared', onDeviceStorageEvent);
1514
+ WebView.onEvent('device_storage_failed', onDeviceStorageEvent);
1515
+
1516
+ function onDeviceStorageEvent(eventType, eventData) {
1517
+ if (eventData.req_id && webAppCallbacks[eventData.req_id]) {
1518
+ var requestData = webAppCallbacks[eventData.req_id];
1519
+ delete webAppCallbacks[eventData.req_id];
1520
+ var res = null, err = null;
1521
+ if (eventType == 'device_storage_failed') {
1522
+ err = eventData.error || 'UNKNOWN_ERROR';
1523
+ } else if (eventType == 'device_storage_key_received') {
1524
+ res = eventData.value;
1525
+ } else {
1526
+ res = true;
1527
+ }
1528
+ if (requestData.callback) {
1529
+ requestData.callback(err, res);
1530
+ }
1531
+ }
1532
+ }
1533
+
1534
+ function invokeStorageMethod(method, params, callback) {
1535
+ if (!versionAtLeast('9.0')) {
1536
+ console.error('[Telegram.WebApp] DeviceStorage is not supported in version ' + webAppVersion);
1537
+ throw Error('WebAppMethodUnsupported');
1538
+ }
1539
+ var req_id = generateCallbackId(16);
1540
+ var req_params = {req_id: req_id};
1541
+ for (var k in params) {
1542
+ req_params[k] = params[k];
1543
+ }
1544
+ webAppCallbacks[req_id] = {
1545
+ callback: callback
1546
+ };
1547
+ WebView.postEvent(method, false, req_params);
1548
+ return deviceStorage;
1549
+ }
1550
+
1551
+ deviceStorage.setItem = function(key, value, callback) {
1552
+ return invokeStorageMethod('web_app_device_storage_save_key', {key: key, value: value}, callback);
1553
+ };
1554
+ deviceStorage.getItem = function(key, callback) {
1555
+ return invokeStorageMethod('web_app_device_storage_get_key', {key: key}, callback);
1556
+ };
1557
+ deviceStorage.removeItem = function(key, callback) {
1558
+ return invokeStorageMethod('web_app_device_storage_save_key', {key: key, value: null}, callback);
1559
+ };
1560
+ deviceStorage.clear = function(callback) {
1561
+ return invokeStorageMethod('web_app_device_storage_clear', {}, callback);
1562
+ };
1563
+ return deviceStorage;
1564
+ })();
1565
+
1566
+ var SecureStorage = (function() {
1567
+ var secureStorage = {};
1568
+
1569
+ WebView.onEvent('secure_storage_key_saved', onSecureStorageEvent);
1570
+ WebView.onEvent('secure_storage_key_received', onSecureStorageEvent);
1571
+ WebView.onEvent('secure_storage_key_restored', onSecureStorageEvent);
1572
+ WebView.onEvent('secure_storage_cleared', onSecureStorageEvent);
1573
+ WebView.onEvent('secure_storage_failed', onSecureStorageEvent);
1574
+
1575
+ function onSecureStorageEvent(eventType, eventData) {
1576
+ if (eventData.req_id && webAppCallbacks[eventData.req_id]) {
1577
+ var requestData = webAppCallbacks[eventData.req_id];
1578
+ delete webAppCallbacks[eventData.req_id];
1579
+ var res = null, err = null, can_restore = null;
1580
+ if (eventType == 'secure_storage_failed') {
1581
+ err = eventData.error || 'UNKNOWN_ERROR';
1582
+ } else if (eventType == 'secure_storage_key_received') {
1583
+ res = eventData.value;
1584
+ if (eventData.can_restore) {
1585
+ can_restore = true;
1586
+ }
1587
+ } else if (eventType == 'secure_storage_key_restored') {
1588
+ res = eventData.value;
1589
+ } else {
1590
+ res = true;
1591
+ }
1592
+ if (requestData.callback) {
1593
+ requestData.callback(err, res, can_restore);
1594
+ }
1595
+ }
1596
+ }
1597
+
1598
+ function invokeStorageMethod(method, params, callback) {
1599
+ if (!versionAtLeast('9.0')) {
1600
+ console.error('[Telegram.WebApp] SecureStorage is not supported in version ' + webAppVersion);
1601
+ throw Error('WebAppMethodUnsupported');
1602
+ }
1603
+ var req_id = generateCallbackId(16);
1604
+ var req_params = {req_id: req_id};
1605
+ for (var k in params) {
1606
+ req_params[k] = params[k];
1607
+ }
1608
+ webAppCallbacks[req_id] = {
1609
+ callback: callback
1610
+ };
1611
+ WebView.postEvent(method, false, req_params);
1612
+ return secureStorage;
1613
+ }
1614
+
1615
+ secureStorage.setItem = function(key, value, callback) {
1616
+ return invokeStorageMethod('web_app_secure_storage_save_key', {key: key, value: value}, callback);
1617
+ };
1618
+ secureStorage.getItem = function(key, callback) {
1619
+ return invokeStorageMethod('web_app_secure_storage_get_key', {key: key}, callback);
1620
+ };
1621
+ secureStorage.restoreItem = function(key, callback) {
1622
+ return invokeStorageMethod('web_app_secure_storage_restore_key', {key: key}, callback);
1623
+ };
1624
+ secureStorage.removeItem = function(key, callback) {
1625
+ return invokeStorageMethod('web_app_secure_storage_save_key', {key: key, value: null}, callback);
1626
+ };
1627
+ secureStorage.clear = function(callback) {
1628
+ return invokeStorageMethod('web_app_secure_storage_clear', {}, callback);
1629
+ };
1630
+ return secureStorage;
1631
+ })();
1632
+
1633
+ var BiometricManager = (function() {
1634
+ var isInited = false;
1635
+ var isBiometricAvailable = false;
1636
+ var biometricType = 'unknown';
1637
+ var isAccessRequested = false;
1638
+ var isAccessGranted = false;
1639
+ var isBiometricTokenSaved = false;
1640
+ var deviceId = '';
1641
+
1642
+ var biometricManager = {};
1643
+ Object.defineProperty(biometricManager, 'isInited', {
1644
+ get: function(){ return isInited; },
1645
+ enumerable: true
1646
+ });
1647
+ Object.defineProperty(biometricManager, 'isBiometricAvailable', {
1648
+ get: function(){ return isInited && isBiometricAvailable; },
1649
+ enumerable: true
1650
+ });
1651
+ Object.defineProperty(biometricManager, 'biometricType', {
1652
+ get: function(){ return biometricType || 'unknown'; },
1653
+ enumerable: true
1654
+ });
1655
+ Object.defineProperty(biometricManager, 'isAccessRequested', {
1656
+ get: function(){ return isAccessRequested; },
1657
+ enumerable: true
1658
+ });
1659
+ Object.defineProperty(biometricManager, 'isAccessGranted', {
1660
+ get: function(){ return isAccessRequested && isAccessGranted; },
1661
+ enumerable: true
1662
+ });
1663
+ Object.defineProperty(biometricManager, 'isBiometricTokenSaved', {
1664
+ get: function(){ return isBiometricTokenSaved; },
1665
+ enumerable: true
1666
+ });
1667
+ Object.defineProperty(biometricManager, 'deviceId', {
1668
+ get: function(){ return deviceId || ''; },
1669
+ enumerable: true
1670
+ });
1671
+
1672
+ var initRequestState = {callbacks: []};
1673
+ var accessRequestState = false;
1674
+ var authRequestState = false;
1675
+ var tokenRequestState = false;
1676
+
1677
+ WebView.onEvent('biometry_info_received', onBiometryInfoReceived);
1678
+ WebView.onEvent('biometry_auth_requested', onBiometryAuthRequested);
1679
+ WebView.onEvent('biometry_token_updated', onBiometryTokenUpdated);
1680
+
1681
+ function onBiometryInfoReceived(eventType, eventData) {
1682
+ isInited = true;
1683
+ if (eventData.available) {
1684
+ isBiometricAvailable = true;
1685
+ biometricType = eventData.type || 'unknown';
1686
+ if (eventData.access_requested) {
1687
+ isAccessRequested = true;
1688
+ isAccessGranted = !!eventData.access_granted;
1689
+ isBiometricTokenSaved = !!eventData.token_saved;
1690
+ } else {
1691
+ isAccessRequested = false;
1692
+ isAccessGranted = false;
1693
+ isBiometricTokenSaved = false;
1694
+ }
1695
+ } else {
1696
+ isBiometricAvailable = false;
1697
+ biometricType = 'unknown';
1698
+ isAccessRequested = false;
1699
+ isAccessGranted = false;
1700
+ isBiometricTokenSaved = false;
1701
+ }
1702
+ deviceId = eventData.device_id || '';
1703
+
1704
+ if (initRequestState.callbacks.length > 0) {
1705
+ for (var i = 0; i < initRequestState.callbacks.length; i++) {
1706
+ var callback = initRequestState.callbacks[i];
1707
+ callback();
1708
+ }
1709
+ initRequestState.callbacks = [];
1710
+ }
1711
+ if (accessRequestState) {
1712
+ var state = accessRequestState;
1713
+ accessRequestState = false;
1714
+ if (state.callback) {
1715
+ state.callback(isAccessGranted);
1716
+ }
1717
+ }
1718
+ receiveWebViewEvent('biometricManagerUpdated');
1719
+ }
1720
+ function onBiometryAuthRequested(eventType, eventData) {
1721
+ var isAuthenticated = (eventData.status == 'authorized'),
1722
+ biometricToken = eventData.token || '';
1723
+ if (authRequestState) {
1724
+ var state = authRequestState;
1725
+ authRequestState = false;
1726
+ if (state.callback) {
1727
+ state.callback(isAuthenticated, isAuthenticated ? biometricToken : null);
1728
+ }
1729
+ }
1730
+ receiveWebViewEvent('biometricAuthRequested', isAuthenticated ? {
1731
+ isAuthenticated: true,
1732
+ biometricToken: biometricToken
1733
+ } : {
1734
+ isAuthenticated: false
1735
+ });
1736
+ }
1737
+ function onBiometryTokenUpdated(eventType, eventData) {
1738
+ var applied = false;
1739
+ if (isBiometricAvailable &&
1740
+ isAccessRequested) {
1741
+ if (eventData.status == 'updated') {
1742
+ isBiometricTokenSaved = true;
1743
+ applied = true;
1744
+ }
1745
+ else if (eventData.status == 'removed') {
1746
+ isBiometricTokenSaved = false;
1747
+ applied = true;
1748
+ }
1749
+ }
1750
+ if (tokenRequestState) {
1751
+ var state = tokenRequestState;
1752
+ tokenRequestState = false;
1753
+ if (state.callback) {
1754
+ state.callback(applied);
1755
+ }
1756
+ }
1757
+ receiveWebViewEvent('biometricTokenUpdated', {
1758
+ isUpdated: applied
1759
+ });
1760
+ }
1761
+
1762
+ function checkVersion() {
1763
+ if (!versionAtLeast('7.2')) {
1764
+ console.warn('[Telegram.WebApp] BiometricManager is not supported in version ' + webAppVersion);
1765
+ return false;
1766
+ }
1767
+ return true;
1768
+ }
1769
+
1770
+ function checkInit() {
1771
+ if (!isInited) {
1772
+ console.error('[Telegram.WebApp] BiometricManager should be inited before using.');
1773
+ throw Error('WebAppBiometricManagerNotInited');
1774
+ }
1775
+ return true;
1776
+ }
1777
+
1778
+ biometricManager.init = function(callback) {
1779
+ if (!checkVersion()) {
1780
+ return biometricManager;
1781
+ }
1782
+ if (isInited) {
1783
+ return biometricManager;
1784
+ }
1785
+ if (callback) {
1786
+ initRequestState.callbacks.push(callback);
1787
+ }
1788
+ WebView.postEvent('web_app_biometry_get_info', false);
1789
+ return biometricManager;
1790
+ };
1791
+ biometricManager.requestAccess = function(params, callback) {
1792
+ if (!checkVersion()) {
1793
+ return biometricManager;
1794
+ }
1795
+ checkInit();
1796
+ if (!isBiometricAvailable) {
1797
+ console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1798
+ throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1799
+ }
1800
+ if (accessRequestState) {
1801
+ console.error('[Telegram.WebApp] Access is already requested');
1802
+ throw Error('WebAppBiometricManagerAccessRequested');
1803
+ }
1804
+ var popup_params = {};
1805
+ if (typeof params.reason !== 'undefined') {
1806
+ var reason = strTrim(params.reason);
1807
+ if (reason.length > 128) {
1808
+ console.error('[Telegram.WebApp] Biometric reason is too long', reason);
1809
+ throw Error('WebAppBiometricRequestAccessParamInvalid');
1810
+ }
1811
+ if (reason.length > 0) {
1812
+ popup_params.reason = reason;
1813
+ }
1814
+ }
1815
+
1816
+ accessRequestState = {
1817
+ callback: callback
1818
+ };
1819
+ WebView.postEvent('web_app_biometry_request_access', false, popup_params);
1820
+ return biometricManager;
1821
+ };
1822
+ biometricManager.authenticate = function(params, callback) {
1823
+ if (!checkVersion()) {
1824
+ return biometricManager;
1825
+ }
1826
+ checkInit();
1827
+ if (!isBiometricAvailable) {
1828
+ console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1829
+ throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1830
+ }
1831
+ if (!isAccessGranted) {
1832
+ console.error('[Telegram.WebApp] Biometric access was not granted by the user.');
1833
+ throw Error('WebAppBiometricManagerBiometricAccessNotGranted');
1834
+ }
1835
+ if (authRequestState) {
1836
+ console.error('[Telegram.WebApp] Authentication request is already in progress.');
1837
+ throw Error('WebAppBiometricManagerAuthenticationRequested');
1838
+ }
1839
+ var popup_params = {};
1840
+ if (typeof params.reason !== 'undefined') {
1841
+ var reason = strTrim(params.reason);
1842
+ if (reason.length > 128) {
1843
+ console.error('[Telegram.WebApp] Biometric reason is too long', reason);
1844
+ throw Error('WebAppBiometricRequestAccessParamInvalid');
1845
+ }
1846
+ if (reason.length > 0) {
1847
+ popup_params.reason = reason;
1848
+ }
1849
+ }
1850
+
1851
+ authRequestState = {
1852
+ callback: callback
1853
+ };
1854
+ WebView.postEvent('web_app_biometry_request_auth', false, popup_params);
1855
+ return biometricManager;
1856
+ };
1857
+ biometricManager.updateBiometricToken = function(token, callback) {
1858
+ if (!checkVersion()) {
1859
+ return biometricManager;
1860
+ }
1861
+ token = token || '';
1862
+ if (token.length > 1024) {
1863
+ console.error('[Telegram.WebApp] Token is too long', token);
1864
+ throw Error('WebAppBiometricManagerTokenInvalid');
1865
+ }
1866
+ checkInit();
1867
+ if (!isBiometricAvailable) {
1868
+ console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1869
+ throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1870
+ }
1871
+ if (!isAccessGranted) {
1872
+ console.error('[Telegram.WebApp] Biometric access was not granted by the user.');
1873
+ throw Error('WebAppBiometricManagerBiometricAccessNotGranted');
1874
+ }
1875
+ if (tokenRequestState) {
1876
+ console.error('[Telegram.WebApp] Token request is already in progress.');
1877
+ throw Error('WebAppBiometricManagerTokenUpdateRequested');
1878
+ }
1879
+ tokenRequestState = {
1880
+ callback: callback
1881
+ };
1882
+ WebView.postEvent('web_app_biometry_update_token', false, {token: token});
1883
+ return biometricManager;
1884
+ };
1885
+ biometricManager.openSettings = function() {
1886
+ if (!checkVersion()) {
1887
+ return biometricManager;
1888
+ }
1889
+ checkInit();
1890
+ if (!isBiometricAvailable) {
1891
+ console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1892
+ throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1893
+ }
1894
+ if (!isAccessRequested) {
1895
+ console.error('[Telegram.WebApp] Biometric access was not requested yet.');
1896
+ throw Error('WebAppBiometricManagerBiometricsAccessNotRequested');
1897
+ }
1898
+ if (isAccessGranted) {
1899
+ console.warn('[Telegram.WebApp] Biometric access was granted by the user, no need to go to settings.');
1900
+ return biometricManager;
1901
+ }
1902
+ WebView.postEvent('web_app_biometry_open_settings', false);
1903
+ return biometricManager;
1904
+ };
1905
+ return biometricManager;
1906
+ })();
1907
+
1908
+ var LocationManager = (function() {
1909
+ var isInited = false;
1910
+ var isLocationAvailable = false;
1911
+ var isAccessRequested = false;
1912
+ var isAccessGranted = false;
1913
+
1914
+ var locationManager = {};
1915
+ Object.defineProperty(locationManager, 'isInited', {
1916
+ get: function(){ return isInited; },
1917
+ enumerable: true
1918
+ });
1919
+ Object.defineProperty(locationManager, 'isLocationAvailable', {
1920
+ get: function(){ return isInited && isLocationAvailable; },
1921
+ enumerable: true
1922
+ });
1923
+ Object.defineProperty(locationManager, 'isAccessRequested', {
1924
+ get: function(){ return isAccessRequested; },
1925
+ enumerable: true
1926
+ });
1927
+ Object.defineProperty(locationManager, 'isAccessGranted', {
1928
+ get: function(){ return isAccessRequested && isAccessGranted; },
1929
+ enumerable: true
1930
+ });
1931
+
1932
+ var initRequestState = {callbacks: []};
1933
+ var getRequestState = {callbacks: []};
1934
+
1935
+ WebView.onEvent('location_checked', onLocationChecked);
1936
+ WebView.onEvent('location_requested', onLocationRequested);
1937
+
1938
+ function onLocationChecked(eventType, eventData) {
1939
+ isInited = true;
1940
+ if (eventData.available) {
1941
+ isLocationAvailable = true;
1942
+ if (eventData.access_requested) {
1943
+ isAccessRequested = true;
1944
+ isAccessGranted = !!eventData.access_granted;
1945
+ } else {
1946
+ isAccessRequested = false;
1947
+ isAccessGranted = false;
1948
+ }
1949
+ } else {
1950
+ isLocationAvailable = false;
1951
+ isAccessRequested = false;
1952
+ isAccessGranted = false;
1953
+ }
1954
+
1955
+ if (initRequestState.callbacks.length > 0) {
1956
+ for (var i = 0; i < initRequestState.callbacks.length; i++) {
1957
+ var callback = initRequestState.callbacks[i];
1958
+ callback();
1959
+ }
1960
+ initRequestState.callbacks = [];
1961
+ }
1962
+ receiveWebViewEvent('locationManagerUpdated');
1963
+ }
1964
+ function onLocationRequested(eventType, eventData) {
1965
+ if (!eventData.available) {
1966
+ locationData = null;
1967
+ } else {
1968
+ var locationData = {
1969
+ latitude: eventData.latitude,
1970
+ longitude: eventData.longitude,
1971
+ altitude: null,
1972
+ course: null,
1973
+ speed: null,
1974
+ horizontal_accuracy: null,
1975
+ vertical_accuracy: null,
1976
+ course_accuracy: null,
1977
+ speed_accuracy: null,
1978
+ };
1979
+ if (typeof eventData.altitude !== 'undefined' && eventData.altitude !== null) {
1980
+ locationData.altitude = eventData.altitude;
1981
+ }
1982
+ if (typeof eventData.course !== 'undefined' && eventData.course !== null) {
1983
+ locationData.course = eventData.course % 360;
1984
+ }
1985
+ if (typeof eventData.speed !== 'undefined' && eventData.speed !== null) {
1986
+ locationData.speed = eventData.speed;
1987
+ }
1988
+ if (typeof eventData.horizontal_accuracy !== 'undefined' && eventData.horizontal_accuracy !== null) {
1989
+ locationData.horizontal_accuracy = eventData.horizontal_accuracy;
1990
+ }
1991
+ if (typeof eventData.vertical_accuracy !== 'undefined' && eventData.vertical_accuracy !== null) {
1992
+ locationData.vertical_accuracy = eventData.vertical_accuracy;
1993
+ }
1994
+ if (typeof eventData.course_accuracy !== 'undefined' && eventData.course_accuracy !== null) {
1995
+ locationData.course_accuracy = eventData.course_accuracy;
1996
+ }
1997
+ if (typeof eventData.speed_accuracy !== 'undefined' && eventData.speed_accuracy !== null) {
1998
+ locationData.speed_accuracy = eventData.speed_accuracy;
1999
+ }
2000
+ }
2001
+ if (!eventData.available ||
2002
+ !isLocationAvailable ||
2003
+ !isAccessRequested ||
2004
+ !isAccessGranted) {
2005
+ initRequestState.callbacks.push(function() {
2006
+ locationResponse(locationData);
2007
+ });
2008
+ WebView.postEvent('web_app_check_location', false);
2009
+ } else {
2010
+ locationResponse(locationData);
2011
+ }
2012
+ }
2013
+ function locationResponse(response) {
2014
+ if (getRequestState.callbacks.length > 0) {
2015
+ for (var i = 0; i < getRequestState.callbacks.length; i++) {
2016
+ var callback = getRequestState.callbacks[i];
2017
+ callback(response);
2018
+ }
2019
+ getRequestState.callbacks = [];
2020
+ }
2021
+ if (response !== null) {
2022
+ receiveWebViewEvent('locationRequested', {
2023
+ locationData: response
2024
+ });
2025
+ }
2026
+ }
2027
+
2028
+ function checkVersion() {
2029
+ if (!versionAtLeast('8.0')) {
2030
+ console.warn('[Telegram.WebApp] LocationManager is not supported in version ' + webAppVersion);
2031
+ return false;
2032
+ }
2033
+ return true;
2034
+ }
2035
+
2036
+ function checkInit() {
2037
+ if (!isInited) {
2038
+ console.error('[Telegram.WebApp] LocationManager should be inited before using.');
2039
+ throw Error('WebAppLocationManagerNotInited');
2040
+ }
2041
+ return true;
2042
+ }
2043
+
2044
+ locationManager.init = function(callback) {
2045
+ if (!checkVersion()) {
2046
+ return locationManager;
2047
+ }
2048
+ if (isInited) {
2049
+ return locationManager;
2050
+ }
2051
+ if (callback) {
2052
+ initRequestState.callbacks.push(callback);
2053
+ }
2054
+ WebView.postEvent('web_app_check_location', false);
2055
+ return locationManager;
2056
+ };
2057
+ locationManager.getLocation = function(callback) {
2058
+ if (!checkVersion()) {
2059
+ return locationManager;
2060
+ }
2061
+ checkInit();
2062
+ if (!isLocationAvailable) {
2063
+ console.error('[Telegram.WebApp] Location is not available on this device.');
2064
+ throw Error('WebAppLocationManagerLocationNotAvailable');
2065
+ }
2066
+
2067
+ getRequestState.callbacks.push(callback);
2068
+ WebView.postEvent('web_app_request_location');
2069
+ return locationManager;
2070
+ };
2071
+ locationManager.openSettings = function() {
2072
+ if (!checkVersion()) {
2073
+ return locationManager;
2074
+ }
2075
+ checkInit();
2076
+ if (!isLocationAvailable) {
2077
+ console.error('[Telegram.WebApp] Location is not available on this device.');
2078
+ throw Error('WebAppLocationManagerLocationNotAvailable');
2079
+ }
2080
+ if (!isAccessRequested) {
2081
+ console.error('[Telegram.WebApp] Location access was not requested yet.');
2082
+ throw Error('WebAppLocationManagerLocationAccessNotRequested');
2083
+ }
2084
+ if (isAccessGranted) {
2085
+ console.warn('[Telegram.WebApp] Location access was granted by the user, no need to go to settings.');
2086
+ return locationManager;
2087
+ }
2088
+ WebView.postEvent('web_app_open_location_settings', false);
2089
+ return locationManager;
2090
+ };
2091
+ return locationManager;
2092
+ })();
2093
+
2094
+ var Accelerometer = (function() {
2095
+ var isStarted = false;
2096
+ var valueX = null, valueY = null, valueZ = null;
2097
+ var startCallbacks = [], stopCallbacks = [];
2098
+
2099
+ var accelerometer = {};
2100
+ Object.defineProperty(accelerometer, 'isStarted', {
2101
+ get: function(){ return isStarted; },
2102
+ enumerable: true
2103
+ });
2104
+ Object.defineProperty(accelerometer, 'x', {
2105
+ get: function(){ return valueX; },
2106
+ enumerable: true
2107
+ });
2108
+ Object.defineProperty(accelerometer, 'y', {
2109
+ get: function(){ return valueY; },
2110
+ enumerable: true
2111
+ });
2112
+ Object.defineProperty(accelerometer, 'z', {
2113
+ get: function(){ return valueZ; },
2114
+ enumerable: true
2115
+ });
2116
+
2117
+ WebView.onEvent('accelerometer_started', onAccelerometerStarted);
2118
+ WebView.onEvent('accelerometer_stopped', onAccelerometerStopped);
2119
+ WebView.onEvent('accelerometer_changed', onAccelerometerChanged);
2120
+ WebView.onEvent('accelerometer_failed', onAccelerometerFailed);
2121
+
2122
+ function onAccelerometerStarted(eventType, eventData) {
2123
+ isStarted = true;
2124
+ if (startCallbacks.length > 0) {
2125
+ for (var i = 0; i < startCallbacks.length; i++) {
2126
+ var callback = startCallbacks[i];
2127
+ callback(true);
2128
+ }
2129
+ startCallbacks = [];
2130
+ }
2131
+ receiveWebViewEvent('accelerometerStarted');
2132
+ }
2133
+ function onAccelerometerStopped(eventType, eventData) {
2134
+ isStarted = false;
2135
+ if (stopCallbacks.length > 0) {
2136
+ for (var i = 0; i < stopCallbacks.length; i++) {
2137
+ var callback = stopCallbacks[i];
2138
+ callback(true);
2139
+ }
2140
+ stopCallbacks = [];
2141
+ }
2142
+ receiveWebViewEvent('accelerometerStopped');
2143
+ }
2144
+ function onAccelerometerChanged(eventType, eventData) {
2145
+ valueX = eventData.x;
2146
+ valueY = eventData.y;
2147
+ valueZ = eventData.z;
2148
+ receiveWebViewEvent('accelerometerChanged');
2149
+ }
2150
+ function onAccelerometerFailed(eventType, eventData) {
2151
+ if (startCallbacks.length > 0) {
2152
+ for (var i = 0; i < startCallbacks.length; i++) {
2153
+ var callback = startCallbacks[i];
2154
+ callback(false);
2155
+ }
2156
+ startCallbacks = [];
2157
+ }
2158
+ receiveWebViewEvent('accelerometerFailed', {
2159
+ error: eventData.error
2160
+ });
2161
+ }
2162
+
2163
+ function checkVersion() {
2164
+ if (!versionAtLeast('8.0')) {
2165
+ console.warn('[Telegram.WebApp] Accelerometer is not supported in version ' + webAppVersion);
2166
+ return false;
2167
+ }
2168
+ return true;
2169
+ }
2170
+
2171
+ accelerometer.start = function(params, callback) {
2172
+ params = params || {};
2173
+ if (!checkVersion()) {
2174
+ return accelerometer;
2175
+ }
2176
+ var req_params = {};
2177
+ var refresh_rate = parseInt(params.refresh_rate || 1000);
2178
+ if (isNaN(refresh_rate) || refresh_rate < 20 || refresh_rate > 1000) {
2179
+ console.warn('[Telegram.WebApp] Accelerometer refresh_rate is invalid', refresh_rate);
2180
+ } else {
2181
+ req_params.refresh_rate = refresh_rate;
2182
+ }
2183
+
2184
+ if (callback) {
2185
+ startCallbacks.push(callback);
2186
+ }
2187
+ WebView.postEvent('web_app_start_accelerometer', false, req_params);
2188
+ return accelerometer;
2189
+ };
2190
+ accelerometer.stop = function(callback) {
2191
+ if (!checkVersion()) {
2192
+ return accelerometer;
2193
+ }
2194
+ if (callback) {
2195
+ stopCallbacks.push(callback);
2196
+ }
2197
+ WebView.postEvent('web_app_stop_accelerometer');
2198
+ return accelerometer;
2199
+ };
2200
+ return accelerometer;
2201
+ })();
2202
+
2203
+ var DeviceOrientation = (function() {
2204
+ var isStarted = false;
2205
+ var valueAlpha = null, valueBeta = null, valueGamma = null, valueAbsolute = false;
2206
+ var startCallbacks = [], stopCallbacks = [];
2207
+
2208
+ var deviceOrientation = {};
2209
+ Object.defineProperty(deviceOrientation, 'isStarted', {
2210
+ get: function(){ return isStarted; },
2211
+ enumerable: true
2212
+ });
2213
+ Object.defineProperty(deviceOrientation, 'absolute', {
2214
+ get: function(){ return valueAbsolute; },
2215
+ enumerable: true
2216
+ });
2217
+ Object.defineProperty(deviceOrientation, 'alpha', {
2218
+ get: function(){ return valueAlpha; },
2219
+ enumerable: true
2220
+ });
2221
+ Object.defineProperty(deviceOrientation, 'beta', {
2222
+ get: function(){ return valueBeta; },
2223
+ enumerable: true
2224
+ });
2225
+ Object.defineProperty(deviceOrientation, 'gamma', {
2226
+ get: function(){ return valueGamma; },
2227
+ enumerable: true
2228
+ });
2229
+
2230
+ WebView.onEvent('device_orientation_started', onDeviceOrientationStarted);
2231
+ WebView.onEvent('device_orientation_stopped', onDeviceOrientationStopped);
2232
+ WebView.onEvent('device_orientation_changed', onDeviceOrientationChanged);
2233
+ WebView.onEvent('device_orientation_failed', onDeviceOrientationFailed);
2234
+
2235
+ function onDeviceOrientationStarted(eventType, eventData) {
2236
+ isStarted = true;
2237
+ if (startCallbacks.length > 0) {
2238
+ for (var i = 0; i < startCallbacks.length; i++) {
2239
+ var callback = startCallbacks[i];
2240
+ callback(true);
2241
+ }
2242
+ startCallbacks = [];
2243
+ }
2244
+ receiveWebViewEvent('deviceOrientationStarted');
2245
+ }
2246
+ function onDeviceOrientationStopped(eventType, eventData) {
2247
+ isStarted = false;
2248
+ if (stopCallbacks.length > 0) {
2249
+ for (var i = 0; i < stopCallbacks.length; i++) {
2250
+ var callback = stopCallbacks[i];
2251
+ callback(true);
2252
+ }
2253
+ stopCallbacks = [];
2254
+ }
2255
+ receiveWebViewEvent('deviceOrientationStopped');
2256
+ }
2257
+ function onDeviceOrientationChanged(eventType, eventData) {
2258
+ valueAbsolute = !!eventData.absolute;
2259
+ valueAlpha = eventData.alpha;
2260
+ valueBeta = eventData.beta;
2261
+ valueGamma = eventData.gamma;
2262
+ receiveWebViewEvent('deviceOrientationChanged');
2263
+ }
2264
+ function onDeviceOrientationFailed(eventType, eventData) {
2265
+ if (startCallbacks.length > 0) {
2266
+ for (var i = 0; i < startCallbacks.length; i++) {
2267
+ var callback = startCallbacks[i];
2268
+ callback(false);
2269
+ }
2270
+ startCallbacks = [];
2271
+ }
2272
+ receiveWebViewEvent('deviceOrientationFailed', {
2273
+ error: eventData.error
2274
+ });
2275
+ }
2276
+
2277
+ function checkVersion() {
2278
+ if (!versionAtLeast('8.0')) {
2279
+ console.warn('[Telegram.WebApp] DeviceOrientation is not supported in version ' + webAppVersion);
2280
+ return false;
2281
+ }
2282
+ return true;
2283
+ }
2284
+
2285
+ deviceOrientation.start = function(params, callback) {
2286
+ params = params || {};
2287
+ if (!checkVersion()) {
2288
+ return deviceOrientation;
2289
+ }
2290
+ var req_params = {};
2291
+ var refresh_rate = parseInt(params.refresh_rate || 1000);
2292
+ if (isNaN(refresh_rate) || refresh_rate < 20 || refresh_rate > 1000) {
2293
+ console.warn('[Telegram.WebApp] DeviceOrientation refresh_rate is invalid', refresh_rate);
2294
+ } else {
2295
+ req_params.refresh_rate = refresh_rate;
2296
+ }
2297
+ req_params.need_absolute = !!params.need_absolute;
2298
+
2299
+ if (callback) {
2300
+ startCallbacks.push(callback);
2301
+ }
2302
+ WebView.postEvent('web_app_start_device_orientation', false, req_params);
2303
+ return deviceOrientation;
2304
+ };
2305
+ deviceOrientation.stop = function(callback) {
2306
+ if (!checkVersion()) {
2307
+ return deviceOrientation;
2308
+ }
2309
+ if (callback) {
2310
+ stopCallbacks.push(callback);
2311
+ }
2312
+ WebView.postEvent('web_app_stop_device_orientation');
2313
+ return deviceOrientation;
2314
+ };
2315
+ return deviceOrientation;
2316
+ })();
2317
+
2318
+ var Gyroscope = (function() {
2319
+ var isStarted = false;
2320
+ var valueX = null, valueY = null, valueZ = null;
2321
+ var startCallbacks = [], stopCallbacks = [];
2322
+
2323
+ var gyroscope = {};
2324
+ Object.defineProperty(gyroscope, 'isStarted', {
2325
+ get: function(){ return isStarted; },
2326
+ enumerable: true
2327
+ });
2328
+ Object.defineProperty(gyroscope, 'x', {
2329
+ get: function(){ return valueX; },
2330
+ enumerable: true
2331
+ });
2332
+ Object.defineProperty(gyroscope, 'y', {
2333
+ get: function(){ return valueY; },
2334
+ enumerable: true
2335
+ });
2336
+ Object.defineProperty(gyroscope, 'z', {
2337
+ get: function(){ return valueZ; },
2338
+ enumerable: true
2339
+ });
2340
+
2341
+ WebView.onEvent('gyroscope_started', onGyroscopeStarted);
2342
+ WebView.onEvent('gyroscope_stopped', onGyroscopeStopped);
2343
+ WebView.onEvent('gyroscope_changed', onGyroscopeChanged);
2344
+ WebView.onEvent('gyroscope_failed', onGyroscopeFailed);
2345
+
2346
+ function onGyroscopeStarted(eventType, eventData) {
2347
+ isStarted = true;
2348
+ if (startCallbacks.length > 0) {
2349
+ for (var i = 0; i < startCallbacks.length; i++) {
2350
+ var callback = startCallbacks[i];
2351
+ callback(true);
2352
+ }
2353
+ startCallbacks = [];
2354
+ }
2355
+ receiveWebViewEvent('gyroscopeStarted');
2356
+ }
2357
+ function onGyroscopeStopped(eventType, eventData) {
2358
+ isStarted = false;
2359
+ if (stopCallbacks.length > 0) {
2360
+ for (var i = 0; i < stopCallbacks.length; i++) {
2361
+ var callback = stopCallbacks[i];
2362
+ callback(true);
2363
+ }
2364
+ stopCallbacks = [];
2365
+ }
2366
+ receiveWebViewEvent('gyroscopeStopped');
2367
+ }
2368
+ function onGyroscopeChanged(eventType, eventData) {
2369
+ valueX = eventData.x;
2370
+ valueY = eventData.y;
2371
+ valueZ = eventData.z;
2372
+ receiveWebViewEvent('gyroscopeChanged');
2373
+ }
2374
+ function onGyroscopeFailed(eventType, eventData) {
2375
+ if (startCallbacks.length > 0) {
2376
+ for (var i = 0; i < startCallbacks.length; i++) {
2377
+ var callback = startCallbacks[i];
2378
+ callback(false);
2379
+ }
2380
+ startCallbacks = [];
2381
+ }
2382
+ receiveWebViewEvent('gyroscopeFailed', {
2383
+ error: eventData.error
2384
+ });
2385
+ }
2386
+
2387
+ function checkVersion() {
2388
+ if (!versionAtLeast('8.0')) {
2389
+ console.warn('[Telegram.WebApp] Gyroscope is not supported in version ' + webAppVersion);
2390
+ return false;
2391
+ }
2392
+ return true;
2393
+ }
2394
+
2395
+ gyroscope.start = function(params, callback) {
2396
+ params = params || {};
2397
+ if (!checkVersion()) {
2398
+ return gyroscope;
2399
+ }
2400
+ var req_params = {};
2401
+ var refresh_rate = parseInt(params.refresh_rate || 1000);
2402
+ if (isNaN(refresh_rate) || refresh_rate < 20 || refresh_rate > 1000) {
2403
+ console.warn('[Telegram.WebApp] Gyroscope refresh_rate is invalid', refresh_rate);
2404
+ } else {
2405
+ req_params.refresh_rate = refresh_rate;
2406
+ }
2407
+
2408
+ if (callback) {
2409
+ startCallbacks.push(callback);
2410
+ }
2411
+ WebView.postEvent('web_app_start_gyroscope', false, req_params);
2412
+ return gyroscope;
2413
+ };
2414
+ gyroscope.stop = function(callback) {
2415
+ if (!checkVersion()) {
2416
+ return gyroscope;
2417
+ }
2418
+ if (callback) {
2419
+ stopCallbacks.push(callback);
2420
+ }
2421
+ WebView.postEvent('web_app_stop_gyroscope');
2422
+ return gyroscope;
2423
+ };
2424
+ return gyroscope;
2425
+ })();
2426
+
2427
+ var webAppInvoices = {};
2428
+ function onInvoiceClosed(eventType, eventData) {
2429
+ if (eventData.slug && webAppInvoices[eventData.slug]) {
2430
+ var invoiceData = webAppInvoices[eventData.slug];
2431
+ delete webAppInvoices[eventData.slug];
2432
+ if (invoiceData.callback) {
2433
+ invoiceData.callback(eventData.status);
2434
+ }
2435
+ receiveWebViewEvent('invoiceClosed', {
2436
+ url: invoiceData.url,
2437
+ status: eventData.status
2438
+ });
2439
+ }
2440
+ }
2441
+
2442
+ var webAppPopupOpened = false;
2443
+ function onPopupClosed(eventType, eventData) {
2444
+ if (webAppPopupOpened) {
2445
+ var popupData = webAppPopupOpened;
2446
+ webAppPopupOpened = false;
2447
+ var button_id = null;
2448
+ if (typeof eventData.button_id !== 'undefined') {
2449
+ button_id = eventData.button_id;
2450
+ }
2451
+ if (popupData.callback) {
2452
+ popupData.callback(button_id);
2453
+ }
2454
+ receiveWebViewEvent('popupClosed', {
2455
+ button_id: button_id
2456
+ });
2457
+ }
2458
+ }
2459
+
2460
+ var webAppScanQrPopupOpened = false;
2461
+ function onQrTextReceived(eventType, eventData) {
2462
+ if (webAppScanQrPopupOpened) {
2463
+ var popupData = webAppScanQrPopupOpened;
2464
+ var data = null;
2465
+ if (typeof eventData.data !== 'undefined') {
2466
+ data = eventData.data;
2467
+ }
2468
+ if (popupData.callback) {
2469
+ if (popupData.callback(data)) {
2470
+ webAppScanQrPopupOpened = false;
2471
+ WebView.postEvent('web_app_close_scan_qr_popup', false);
2472
+ }
2473
+ }
2474
+ receiveWebViewEvent('qrTextReceived', {
2475
+ data: data
2476
+ });
2477
+ }
2478
+ }
2479
+ function onScanQrPopupClosed(eventType, eventData) {
2480
+ webAppScanQrPopupOpened = false;
2481
+ receiveWebViewEvent('scanQrPopupClosed');
2482
+ }
2483
+
2484
+ function onClipboardTextReceived(eventType, eventData) {
2485
+ if (eventData.req_id && webAppCallbacks[eventData.req_id]) {
2486
+ var requestData = webAppCallbacks[eventData.req_id];
2487
+ delete webAppCallbacks[eventData.req_id];
2488
+ var data = null;
2489
+ if (typeof eventData.data !== 'undefined') {
2490
+ data = eventData.data;
2491
+ }
2492
+ if (requestData.callback) {
2493
+ requestData.callback(data);
2494
+ }
2495
+ receiveWebViewEvent('clipboardTextReceived', {
2496
+ data: data
2497
+ });
2498
+ }
2499
+ }
2500
+
2501
+ var WebAppWriteAccessRequested = false;
2502
+ function onWriteAccessRequested(eventType, eventData) {
2503
+ if (WebAppWriteAccessRequested) {
2504
+ var requestData = WebAppWriteAccessRequested;
2505
+ WebAppWriteAccessRequested = false;
2506
+ if (requestData.callback) {
2507
+ requestData.callback(eventData.status == 'allowed');
2508
+ }
2509
+ receiveWebViewEvent('writeAccessRequested', {
2510
+ status: eventData.status
2511
+ });
2512
+ }
2513
+ }
2514
+
2515
+ function getRequestedContact(callback, timeout) {
2516
+ var reqTo, fallbackTo, reqDelay = 0;
2517
+ var reqInvoke = function() {
2518
+ invokeCustomMethod('getRequestedContact', {}, function(err, res) {
2519
+ if (res && res.length) {
2520
+ clearTimeout(fallbackTo);
2521
+ callback(res);
2522
+ } else {
2523
+ reqDelay += 50;
2524
+ reqTo = setTimeout(reqInvoke, reqDelay);
2525
+ }
2526
+ });
2527
+ };
2528
+ var fallbackInvoke = function() {
2529
+ clearTimeout(reqTo);
2530
+ callback('');
2531
+ };
2532
+ fallbackTo = setTimeout(fallbackInvoke, timeout);
2533
+ reqInvoke();
2534
+ }
2535
+
2536
+ var WebAppContactRequested = false;
2537
+ function onPhoneRequested(eventType, eventData) {
2538
+ if (WebAppContactRequested) {
2539
+ var requestData = WebAppContactRequested;
2540
+ WebAppContactRequested = false;
2541
+ var requestSent = eventData.status == 'sent';
2542
+ var webViewEvent = {
2543
+ status: eventData.status
2544
+ };
2545
+ if (requestSent) {
2546
+ getRequestedContact(function(res) {
2547
+ if (res && res.length) {
2548
+ webViewEvent.response = res;
2549
+ webViewEvent.responseUnsafe = Utils.urlParseQueryString(res);
2550
+ for (var key in webViewEvent.responseUnsafe) {
2551
+ var val = webViewEvent.responseUnsafe[key];
2552
+ try {
2553
+ if (val.substr(0, 1) == '{' && val.substr(-1) == '}' ||
2554
+ val.substr(0, 1) == '[' && val.substr(-1) == ']') {
2555
+ webViewEvent.responseUnsafe[key] = JSON.parse(val);
2556
+ }
2557
+ } catch (e) {}
2558
+ }
2559
+ }
2560
+ if (requestData.callback) {
2561
+ requestData.callback(requestSent, webViewEvent);
2562
+ }
2563
+ receiveWebViewEvent('contactRequested', webViewEvent);
2564
+ }, 3000);
2565
+ } else {
2566
+ if (requestData.callback) {
2567
+ requestData.callback(requestSent, webViewEvent);
2568
+ }
2569
+ receiveWebViewEvent('contactRequested', webViewEvent);
2570
+ }
2571
+ }
2572
+ }
2573
+
2574
+ var webAppDownloadFileRequested = false;
2575
+ function onFileDownloadRequested(eventType, eventData) {
2576
+ if (webAppDownloadFileRequested) {
2577
+ var requestData = webAppDownloadFileRequested;
2578
+ webAppDownloadFileRequested = false;
2579
+ var isDownloading = eventData.status == 'downloading';
2580
+ if (requestData.callback) {
2581
+ requestData.callback(isDownloading);
2582
+ }
2583
+ receiveWebViewEvent('fileDownloadRequested', {
2584
+ status: isDownloading ? 'downloading' : 'cancelled'
2585
+ });
2586
+ }
2587
+ }
2588
+
2589
+ function onCustomMethodInvoked(eventType, eventData) {
2590
+ if (eventData.req_id && webAppCallbacks[eventData.req_id]) {
2591
+ var requestData = webAppCallbacks[eventData.req_id];
2592
+ delete webAppCallbacks[eventData.req_id];
2593
+ var res = null, err = null;
2594
+ if (typeof eventData.result !== 'undefined') {
2595
+ res = eventData.result;
2596
+ }
2597
+ if (typeof eventData.error !== 'undefined') {
2598
+ err = eventData.error;
2599
+ }
2600
+ if (requestData.callback) {
2601
+ requestData.callback(err, res);
2602
+ }
2603
+ }
2604
+ }
2605
+
2606
+ function invokeCustomMethod(method, params, callback) {
2607
+ if (!versionAtLeast('6.9')) {
2608
+ console.error('[Telegram.WebApp] Method invokeCustomMethod is not supported in version ' + webAppVersion);
2609
+ throw Error('WebAppMethodUnsupported');
2610
+ }
2611
+ var req_id = generateCallbackId(16);
2612
+ var req_params = {req_id: req_id, method: method, params: params || {}};
2613
+ webAppCallbacks[req_id] = {
2614
+ callback: callback
2615
+ };
2616
+ WebView.postEvent('web_app_invoke_custom_method', false, req_params);
2617
+ };
2618
+
2619
+ if (!window.Telegram) {
2620
+ window.Telegram = {};
2621
+ }
2622
+
2623
+ Object.defineProperty(WebApp, 'initData', {
2624
+ get: function(){ return webAppInitData; },
2625
+ enumerable: true
2626
+ });
2627
+ Object.defineProperty(WebApp, 'initDataUnsafe', {
2628
+ get: function(){ return webAppInitDataUnsafe; },
2629
+ enumerable: true
2630
+ });
2631
+ Object.defineProperty(WebApp, 'version', {
2632
+ get: function(){ return webAppVersion; },
2633
+ enumerable: true
2634
+ });
2635
+ Object.defineProperty(WebApp, 'platform', {
2636
+ get: function(){ return webAppPlatform; },
2637
+ enumerable: true
2638
+ });
2639
+ Object.defineProperty(WebApp, 'colorScheme', {
2640
+ get: function(){ return colorScheme; },
2641
+ enumerable: true
2642
+ });
2643
+ Object.defineProperty(WebApp, 'themeParams', {
2644
+ get: function(){ return themeParams; },
2645
+ enumerable: true
2646
+ });
2647
+ Object.defineProperty(WebApp, 'isExpanded', {
2648
+ get: function(){ return isExpanded; },
2649
+ enumerable: true
2650
+ });
2651
+ Object.defineProperty(WebApp, 'viewportHeight', {
2652
+ get: function(){ return (viewportHeight === false ? window.innerHeight : viewportHeight) - bottomBarHeight; },
2653
+ enumerable: true
2654
+ });
2655
+ Object.defineProperty(WebApp, 'viewportStableHeight', {
2656
+ get: function(){ return (viewportStableHeight === false ? window.innerHeight : viewportStableHeight) - bottomBarHeight; },
2657
+ enumerable: true
2658
+ });
2659
+ Object.defineProperty(WebApp, 'safeAreaInset', {
2660
+ get: function(){ return safeAreaInset; },
2661
+ enumerable: true
2662
+ });
2663
+ Object.defineProperty(WebApp, 'contentSafeAreaInset', {
2664
+ get: function(){ return contentSafeAreaInset; },
2665
+ enumerable: true
2666
+ });
2667
+ Object.defineProperty(WebApp, 'isClosingConfirmationEnabled', {
2668
+ set: function(val){ setClosingConfirmation(val); },
2669
+ get: function(){ return isClosingConfirmationEnabled; },
2670
+ enumerable: true
2671
+ });
2672
+ Object.defineProperty(WebApp, 'isVerticalSwipesEnabled', {
2673
+ set: function(val){ toggleVerticalSwipes(val); },
2674
+ get: function(){ return isVerticalSwipesEnabled; },
2675
+ enumerable: true
2676
+ });
2677
+ Object.defineProperty(WebApp, 'isFullscreen', {
2678
+ get: function(){ return webAppIsFullscreen; },
2679
+ enumerable: true
2680
+ });
2681
+ Object.defineProperty(WebApp, 'isOrientationLocked', {
2682
+ set: function(val){ toggleOrientationLock(val); },
2683
+ get: function(){ return webAppIsOrientationLocked; },
2684
+ enumerable: true
2685
+ });
2686
+ Object.defineProperty(WebApp, 'isActive', {
2687
+ get: function(){ return webAppIsActive; },
2688
+ enumerable: true
2689
+ });
2690
+ Object.defineProperty(WebApp, 'headerColor', {
2691
+ set: function(val){ setHeaderColor(val); },
2692
+ get: function(){ return getHeaderColor(); },
2693
+ enumerable: true
2694
+ });
2695
+ Object.defineProperty(WebApp, 'backgroundColor', {
2696
+ set: function(val){ setBackgroundColor(val); },
2697
+ get: function(){ return getBackgroundColor(); },
2698
+ enumerable: true
2699
+ });
2700
+ Object.defineProperty(WebApp, 'bottomBarColor', {
2701
+ set: function(val){ setBottomBarColor(val); },
2702
+ get: function(){ return getBottomBarColor(); },
2703
+ enumerable: true
2704
+ });
2705
+ Object.defineProperty(WebApp, 'BackButton', {
2706
+ value: BackButton,
2707
+ enumerable: true
2708
+ });
2709
+ Object.defineProperty(WebApp, 'MainButton', {
2710
+ value: MainButton,
2711
+ enumerable: true
2712
+ });
2713
+ Object.defineProperty(WebApp, 'SecondaryButton', {
2714
+ value: SecondaryButton,
2715
+ enumerable: true
2716
+ });
2717
+ Object.defineProperty(WebApp, 'SettingsButton', {
2718
+ value: SettingsButton,
2719
+ enumerable: true
2720
+ });
2721
+ Object.defineProperty(WebApp, 'HapticFeedback', {
2722
+ value: HapticFeedback,
2723
+ enumerable: true
2724
+ });
2725
+ Object.defineProperty(WebApp, 'CloudStorage', {
2726
+ value: CloudStorage,
2727
+ enumerable: true
2728
+ });
2729
+ Object.defineProperty(WebApp, 'DeviceStorage', {
2730
+ value: DeviceStorage,
2731
+ enumerable: true
2732
+ });
2733
+ Object.defineProperty(WebApp, 'SecureStorage', {
2734
+ value: SecureStorage,
2735
+ enumerable: true
2736
+ });
2737
+ Object.defineProperty(WebApp, 'BiometricManager', {
2738
+ value: BiometricManager,
2739
+ enumerable: true
2740
+ });
2741
+ Object.defineProperty(WebApp, 'Accelerometer', {
2742
+ value: Accelerometer,
2743
+ enumerable: true
2744
+ });
2745
+ Object.defineProperty(WebApp, 'DeviceOrientation', {
2746
+ value: DeviceOrientation,
2747
+ enumerable: true
2748
+ });
2749
+ Object.defineProperty(WebApp, 'Gyroscope', {
2750
+ value: Gyroscope,
2751
+ enumerable: true
2752
+ });
2753
+ Object.defineProperty(WebApp, 'LocationManager', {
2754
+ value: LocationManager,
2755
+ enumerable: true
2756
+ });
2757
+ WebApp.isVersionAtLeast = function(ver) {
2758
+ return versionAtLeast(ver);
2759
+ };
2760
+ WebApp.setHeaderColor = function(color_key) {
2761
+ WebApp.headerColor = color_key;
2762
+ };
2763
+ WebApp.setBackgroundColor = function(color) {
2764
+ WebApp.backgroundColor = color;
2765
+ };
2766
+ WebApp.setBottomBarColor = function(color) {
2767
+ WebApp.bottomBarColor = color;
2768
+ };
2769
+ WebApp.enableClosingConfirmation = function() {
2770
+ WebApp.isClosingConfirmationEnabled = true;
2771
+ };
2772
+ WebApp.disableClosingConfirmation = function() {
2773
+ WebApp.isClosingConfirmationEnabled = false;
2774
+ };
2775
+ WebApp.enableVerticalSwipes = function() {
2776
+ WebApp.isVerticalSwipesEnabled = true;
2777
+ };
2778
+ WebApp.disableVerticalSwipes = function() {
2779
+ WebApp.isVerticalSwipesEnabled = false;
2780
+ };
2781
+ WebApp.lockOrientation = function() {
2782
+ WebApp.isOrientationLocked = true;
2783
+ };
2784
+ WebApp.unlockOrientation = function() {
2785
+ WebApp.isOrientationLocked = false;
2786
+ };
2787
+ WebApp.requestFullscreen = function() {
2788
+ if (!versionAtLeast('8.0')) {
2789
+ console.error('[Telegram.WebApp] Method requestFullscreen is not supported in version ' + webAppVersion);
2790
+ throw Error('WebAppMethodUnsupported');
2791
+ }
2792
+ WebView.postEvent('web_app_request_fullscreen');
2793
+ };
2794
+ WebApp.exitFullscreen = function() {
2795
+ if (!versionAtLeast('8.0')) {
2796
+ console.error('[Telegram.WebApp] Method exitFullscreen is not supported in version ' + webAppVersion);
2797
+ throw Error('WebAppMethodUnsupported');
2798
+ }
2799
+ WebView.postEvent('web_app_exit_fullscreen');
2800
+ };
2801
+ WebApp.addToHomeScreen = function() {
2802
+ if (!versionAtLeast('8.0')) {
2803
+ console.error('[Telegram.WebApp] Method addToHomeScreen is not supported in version ' + webAppVersion);
2804
+ throw Error('WebAppMethodUnsupported');
2805
+ }
2806
+ WebView.postEvent('web_app_add_to_home_screen');
2807
+ };
2808
+ WebApp.checkHomeScreenStatus = function(callback) {
2809
+ if (!versionAtLeast('8.0')) {
2810
+ console.error('[Telegram.WebApp] Method checkHomeScreenStatus is not supported in version ' + webAppVersion);
2811
+ throw Error('WebAppMethodUnsupported');
2812
+ }
2813
+ if (callback) {
2814
+ homeScreenCallbacks.push(callback);
2815
+ }
2816
+ WebView.postEvent('web_app_check_home_screen');
2817
+ };
2818
+ WebApp.onEvent = function(eventType, callback) {
2819
+ onWebViewEvent(eventType, callback);
2820
+ };
2821
+ WebApp.offEvent = function(eventType, callback) {offWebViewEvent(eventType, callback);
2822
+ };
2823
+ WebApp.sendData = function (data) {
2824
+ if (!data || !data.length) {
2825
+ console.error('[Telegram.WebApp] Data is required', data);
2826
+ throw Error('WebAppDataInvalid');
2827
+ }
2828
+ if (byteLength(data) > 4096) {
2829
+ console.error('[Telegram.WebApp] Data is too long', data);
2830
+ throw Error('WebAppDataInvalid');
2831
+ }
2832
+ WebView.postEvent('web_app_data_send', false, {data: data});
2833
+ };
2834
+ WebApp.switchInlineQuery = function (query, choose_chat_types) {
2835
+ if (!versionAtLeast('6.6')) {
2836
+ console.error('[Telegram.WebApp] Method switchInlineQuery is not supported in version ' + webAppVersion);
2837
+ throw Error('WebAppMethodUnsupported');
2838
+ }
2839
+ if (!initParams.tgWebAppBotInline) {
2840
+ console.error('[Telegram.WebApp] Inline mode is disabled for this bot. Read more about inline mode: https://core.telegram.org/bots/inline');
2841
+ throw Error('WebAppInlineModeDisabled');
2842
+ }
2843
+ query = query || '';
2844
+ if (query.length > 256) {
2845
+ console.error('[Telegram.WebApp] Inline query is too long', query);
2846
+ throw Error('WebAppInlineQueryInvalid');
2847
+ }
2848
+ var chat_types = [];
2849
+ if (choose_chat_types) {
2850
+ if (!Array.isArray(choose_chat_types)) {
2851
+ console.error('[Telegram.WebApp] Choose chat types should be an array', choose_chat_types);
2852
+ throw Error('WebAppInlineChooseChatTypesInvalid');
2853
+ }
2854
+ var good_types = {users: 1, bots: 1, groups: 1, channels: 1};
2855
+ for (var i = 0; i < choose_chat_types.length; i++) {
2856
+ var chat_type = choose_chat_types[i];
2857
+ if (!good_types[chat_type]) {
2858
+ console.error('[Telegram.WebApp] Choose chat type is invalid', chat_type);
2859
+ throw Error('WebAppInlineChooseChatTypeInvalid');
2860
+ }
2861
+ if (good_types[chat_type] != 2) {
2862
+ good_types[chat_type] = 2;
2863
+ chat_types.push(chat_type);
2864
+ }
2865
+ }
2866
+ }
2867
+ WebView.postEvent('web_app_switch_inline_query', false, {query: query, chat_types: chat_types});
2868
+ };
2869
+ WebApp.openLink = function (url, options) {
2870
+ var a = document.createElement('A');
2871
+ a.href = url;
2872
+ if (a.protocol != 'http:' &&
2873
+ a.protocol != 'https:') {
2874
+ console.error('[Telegram.WebApp] Url protocol is not supported', url);
2875
+ throw Error('WebAppTgUrlInvalid');
2876
+ }
2877
+ var url = a.href;
2878
+ options = options || {};
2879
+ if (versionAtLeast('6.1')) {
2880
+ var req_params = {url: url};
2881
+ if (versionAtLeast('6.4') && options.try_instant_view) {
2882
+ req_params.try_instant_view = true;
2883
+ }
2884
+ if (versionAtLeast('7.6') && options.try_browser) {
2885
+ req_params.try_browser = options.try_browser;
2886
+ }
2887
+ WebView.postEvent('web_app_open_link', false, req_params);
2888
+ } else {
2889
+ window.open(url, '_blank');
2890
+ }
2891
+ };
2892
+ WebApp.openTelegramLink = function (url, options) {
2893
+ var a = document.createElement('A');
2894
+ a.href = url;
2895
+ if (a.protocol != 'http:' &&
2896
+ a.protocol != 'https:') {
2897
+ console.error('[Telegram.WebApp] Url protocol is not supported', url);
2898
+ throw Error('WebAppTgUrlInvalid');
2899
+ }
2900
+ if (a.hostname != 't.me') {
2901
+ console.error('[Telegram.WebApp] Url host is not supported', url);
2902
+ throw Error('WebAppTgUrlInvalid');
2903
+ }
2904
+ var path_full = a.pathname + a.search;
2905
+ options = options || {};
2906
+ if (isIframe || versionAtLeast('6.1')) {
2907
+ var req_params = {path_full: path_full};
2908
+ if (options.force_request) {
2909
+ req_params.force_request = true;
2910
+ }
2911
+ WebView.postEvent('web_app_open_tg_link', false, req_params);
2912
+ } else {
2913
+ location.href = 'https://t.me' + path_full;
2914
+ }
2915
+ };
2916
+ WebApp.openInvoice = function (url, callback) {
2917
+ var a = document.createElement('A'), match, slug;
2918
+ a.href = url;
2919
+ if (a.protocol != 'http:' &&
2920
+ a.protocol != 'https:' ||
2921
+ a.hostname != 't.me' ||
2922
+ !(match = a.pathname.match(/^\/(\$|invoice\/)([A-Za-z0-9\-_=]+)$/)) ||
2923
+ !(slug = match[2])) {
2924
+ console.error('[Telegram.WebApp] Invoice url is invalid', url);
2925
+ throw Error('WebAppInvoiceUrlInvalid');
2926
+ }
2927
+ if (!versionAtLeast('6.1')) {
2928
+ console.error('[Telegram.WebApp] Method openInvoice is not supported in version ' + webAppVersion);
2929
+ throw Error('WebAppMethodUnsupported');
2930
+ }
2931
+ if (webAppInvoices[slug]) {
2932
+ console.error('[Telegram.WebApp] Invoice is already opened');
2933
+ throw Error('WebAppInvoiceOpened');
2934
+ }
2935
+ webAppInvoices[slug] = {
2936
+ url: url,
2937
+ callback: callback
2938
+ };
2939
+ WebView.postEvent('web_app_open_invoice', false, {slug: slug});
2940
+ };
2941
+ WebApp.showPopup = function (params, callback) {
2942
+ if (!versionAtLeast('6.2')) {
2943
+ console.error('[Telegram.WebApp] Method showPopup is not supported in version ' + webAppVersion);
2944
+ throw Error('WebAppMethodUnsupported');
2945
+ }
2946
+ if (webAppPopupOpened) {
2947
+ console.error('[Telegram.WebApp] Popup is already opened');
2948
+ throw Error('WebAppPopupOpened');
2949
+ }
2950
+ var title = '';
2951
+ var message = '';
2952
+ var buttons = [];
2953
+ var popup_buttons = {};
2954
+ var popup_params = {};
2955
+ if (typeof params.title !== 'undefined') {
2956
+ title = strTrim(params.title);
2957
+ if (title.length > 64) {
2958
+ console.error('[Telegram.WebApp] Popup title is too long', title);
2959
+ throw Error('WebAppPopupParamInvalid');
2960
+ }
2961
+ if (title.length > 0) {
2962
+ popup_params.title = title;
2963
+ }
2964
+ }
2965
+ if (typeof params.message !== 'undefined') {
2966
+ message = strTrim(params.message);
2967
+ }
2968
+ if (!message.length) {
2969
+ console.error('[Telegram.WebApp] Popup message is required', params.message);
2970
+ throw Error('WebAppPopupParamInvalid');
2971
+ }
2972
+ if (message.length > 256) {
2973
+ console.error('[Telegram.WebApp] Popup message is too long', message);
2974
+ throw Error('WebAppPopupParamInvalid');
2975
+ }
2976
+ popup_params.message = message;
2977
+ if (typeof params.buttons !== 'undefined') {
2978
+ if (!Array.isArray(params.buttons)) {
2979
+ console.error('[Telegram.WebApp] Popup buttons should be an array', params.buttons);
2980
+ throw Error('WebAppPopupParamInvalid');
2981
+ }
2982
+ for (var i = 0; i < params.buttons.length; i++) {
2983
+ var button = params.buttons[i];
2984
+ var btn = {};
2985
+ var id = '';
2986
+ if (typeof button.id !== 'undefined') {
2987
+ id = button.id.toString();
2988
+ if (id.length > 64) {
2989
+ console.error('[Telegram.WebApp] Popup button id is too long', id);
2990
+ throw Error('WebAppPopupParamInvalid');
2991
+ }
2992
+ }
2993
+ btn.id = id;
2994
+ var button_type = button.type;
2995
+ if (typeof button_type === 'undefined') {
2996
+ button_type = 'default';
2997
+ }
2998
+ btn.type = button_type;
2999
+ if (button_type == 'ok' ||
3000
+ button_type == 'close' ||
3001
+ button_type == 'cancel') {
3002
+ // no params needed
3003
+ } else if (button_type == 'default' ||
3004
+ button_type == 'destructive') {
3005
+ var text = '';
3006
+ if (typeof button.text !== 'undefined') {
3007
+ text = strTrim(button.text);
3008
+ }
3009
+ if (!text.length) {
3010
+ console.error('[Telegram.WebApp] Popup button text is required for type ' + button_type, button.text);
3011
+ throw Error('WebAppPopupParamInvalid');
3012
+ }
3013
+ if (text.length > 64) {
3014
+ console.error('[Telegram.WebApp] Popup button text is too long', text);
3015
+ throw Error('WebAppPopupParamInvalid');
3016
+ }
3017
+ btn.text = text;
3018
+ } else {
3019
+ console.error('[Telegram.WebApp] Popup button type is invalid', button_type);
3020
+ throw Error('WebAppPopupParamInvalid');
3021
+ }
3022
+ buttons.push(btn);
3023
+ }
3024
+ } else {
3025
+ buttons.push({id: '', type: 'close'});
3026
+ }
3027
+ if (buttons.length < 1) {
3028
+ console.error('[Telegram.WebApp] Popup should have at least one button');
3029
+ throw Error('WebAppPopupParamInvalid');
3030
+ }
3031
+ if (buttons.length > 3) {
3032
+ console.error('[Telegram.WebApp] Popup should not have more than 3 buttons');
3033
+ throw Error('WebAppPopupParamInvalid');
3034
+ }
3035
+ popup_params.buttons = buttons;
3036
+
3037
+ webAppPopupOpened = {
3038
+ callback: callback
3039
+ };
3040
+ WebView.postEvent('web_app_open_popup', false, popup_params);
3041
+ };
3042
+ WebApp.showAlert = function (message, callback) {
3043
+ WebApp.showPopup({
3044
+ message: message
3045
+ }, callback ? function(){ callback(); } : null);
3046
+ };
3047
+ WebApp.showConfirm = function (message, callback) {
3048
+ WebApp.showPopup({
3049
+ message: message,
3050
+ buttons: [
3051
+ {type: 'ok', id: 'ok'},
3052
+ {type: 'cancel'}
3053
+ ]
3054
+ }, callback ? function (button_id) {
3055
+ callback(button_id == 'ok');
3056
+ } : null);
3057
+ };
3058
+ WebApp.showScanQrPopup = function (params, callback) {
3059
+ if (!versionAtLeast('6.4')) {
3060
+ console.error('[Telegram.WebApp] Method showScanQrPopup is not supported in version ' + webAppVersion);
3061
+ throw Error('WebAppMethodUnsupported');
3062
+ }
3063
+ if (webAppScanQrPopupOpened) {
3064
+ console.error('[Telegram.WebApp] Popup is already opened');
3065
+ throw Error('WebAppScanQrPopupOpened');
3066
+ }
3067
+ var text = '';
3068
+ var popup_params = {};
3069
+ if (typeof params.text !== 'undefined') {
3070
+ text = strTrim(params.text);
3071
+ if (text.length > 64) {
3072
+ console.error('[Telegram.WebApp] Scan QR popup text is too long', text);
3073
+ throw Error('WebAppScanQrPopupParamInvalid');
3074
+ }
3075
+ if (text.length > 0) {
3076
+ popup_params.text = text;
3077
+ }
3078
+ }
3079
+
3080
+ webAppScanQrPopupOpened = {
3081
+ callback: callback
3082
+ };
3083
+ WebView.postEvent('web_app_open_scan_qr_popup', false, popup_params);
3084
+ };
3085
+ WebApp.closeScanQrPopup = function () {
3086
+ if (!versionAtLeast('6.4')) {
3087
+ console.error('[Telegram.WebApp] Method closeScanQrPopup is not supported in version ' + webAppVersion);
3088
+ throw Error('WebAppMethodUnsupported');
3089
+ }
3090
+
3091
+ webAppScanQrPopupOpened = false;
3092
+ WebView.postEvent('web_app_close_scan_qr_popup', false);
3093
+ };
3094
+ WebApp.readTextFromClipboard = function (callback) {
3095
+ if (!versionAtLeast('6.4')) {
3096
+ console.error('[Telegram.WebApp] Method readTextFromClipboard is not supported in version ' + webAppVersion);
3097
+ throw Error('WebAppMethodUnsupported');
3098
+ }
3099
+ var req_id = generateCallbackId(16);
3100
+ var req_params = {req_id: req_id};
3101
+ webAppCallbacks[req_id] = {
3102
+ callback: callback
3103
+ };
3104
+ WebView.postEvent('web_app_read_text_from_clipboard', false, req_params);
3105
+ };
3106
+ WebApp.requestWriteAccess = function (callback) {
3107
+ if (!versionAtLeast('6.9')) {
3108
+ console.error('[Telegram.WebApp] Method requestWriteAccess is not supported in version ' + webAppVersion);
3109
+ throw Error('WebAppMethodUnsupported');
3110
+ }
3111
+ if (WebAppWriteAccessRequested) {
3112
+ console.error('[Telegram.WebApp] Write access is already requested');
3113
+ throw Error('WebAppWriteAccessRequested');
3114
+ }
3115
+ WebAppWriteAccessRequested = {
3116
+ callback: callback
3117
+ };
3118
+ WebView.postEvent('web_app_request_write_access');
3119
+ };
3120
+ WebApp.requestContact = function (callback) {
3121
+ if (!versionAtLeast('6.9')) {
3122
+ console.error('[Telegram.WebApp] Method requestContact is not supported in version ' + webAppVersion);
3123
+ throw Error('WebAppMethodUnsupported');
3124
+ }
3125
+ if (WebAppContactRequested) {
3126
+ console.error('[Telegram.WebApp] Contact is already requested');
3127
+ throw Error('WebAppContactRequested');
3128
+ }
3129
+ WebAppContactRequested = {
3130
+ callback: callback
3131
+ };
3132
+ WebView.postEvent('web_app_request_phone');
3133
+ };
3134
+ WebApp.downloadFile = function (params, callback) {
3135
+ if (!versionAtLeast('8.0')) {
3136
+ console.error('[Telegram.WebApp] Method downloadFile is not supported in version ' + webAppVersion);
3137
+ throw Error('WebAppMethodUnsupported');
3138
+ }
3139
+ if (webAppDownloadFileRequested) {
3140
+ console.error('[Telegram.WebApp] Popup is already opened');
3141
+ throw Error('WebAppDownloadFilePopupOpened');
3142
+ }
3143
+ var a = document.createElement('A');
3144
+
3145
+ var dl_params = {};
3146
+ if (!params || !params.url || !params.url.length) {
3147
+ console.error('[Telegram.WebApp] Url is required');
3148
+ throw Error('WebAppDownloadFileParamInvalid');
3149
+ }
3150
+ a.href = params.url;
3151
+ if (a.protocol != 'https:') {
3152
+ console.error('[Telegram.WebApp] Url protocol is not supported', url);
3153
+ throw Error('WebAppDownloadFileParamInvalid');
3154
+ }
3155
+ dl_params.url = a.href;
3156
+
3157
+ if (!params || !params.file_name || !params.file_name.length) {
3158
+ console.error('[Telegram.WebApp] File name is required');
3159
+ throw Error('WebAppDownloadFileParamInvalid');
3160
+ }
3161
+ dl_params.file_name = params.file_name;
3162
+
3163
+ webAppDownloadFileRequested = {
3164
+ callback: callback
3165
+ };
3166
+ WebView.postEvent('web_app_request_file_download', false, dl_params);
3167
+ };
3168
+ WebApp.shareToStory = function (media_url, params) {
3169
+ params = params || {};
3170
+ if (!versionAtLeast('7.8')) {
3171
+ console.error('[Telegram.WebApp] Method shareToStory is not supported in version ' + webAppVersion);
3172
+ throw Error('WebAppMethodUnsupported');
3173
+ }
3174
+ var a = document.createElement('A');
3175
+ a.href = media_url;
3176
+ if (a.protocol != 'http:' &&
3177
+ a.protocol != 'https:') {
3178
+ console.error('[Telegram.WebApp] Media url protocol is not supported', url);
3179
+ throw Error('WebAppMediaUrlInvalid');
3180
+ }
3181
+ var share_params = {};
3182
+ share_params.media_url = a.href;
3183
+ if (typeof params.text !== 'undefined') {
3184
+ var text = strTrim(params.text);
3185
+ if (text.length > 2048) {
3186
+ console.error('[Telegram.WebApp] Text is too long', text);
3187
+ throw Error('WebAppShareToStoryParamInvalid');
3188
+ }
3189
+ if (text.length > 0) {
3190
+ share_params.text = text;
3191
+ }
3192
+ }
3193
+ if (typeof params.widget_link !== 'undefined') {
3194
+ params.widget_link = params.widget_link || {};
3195
+ a.href = params.widget_link.url;
3196
+ if (a.protocol != 'http:' &&
3197
+ a.protocol != 'https:') {
3198
+ console.error('[Telegram.WebApp] Link protocol is not supported', url);
3199
+ throw Error('WebAppShareToStoryParamInvalid');
3200
+ }
3201
+ var widget_link = {
3202
+ url: a.href
3203
+ };
3204
+ if (typeof params.widget_link.name !== 'undefined') {
3205
+ var link_name = strTrim(params.widget_link.name);
3206
+ if (link_name.length > 48) {
3207
+ console.error('[Telegram.WebApp] Link name is too long', link_name);
3208
+ throw Error('WebAppShareToStoryParamInvalid');
3209
+ }
3210
+ if (link_name.length > 0) {
3211
+ widget_link.name = link_name;
3212
+ }
3213
+ }
3214
+ share_params.widget_link = widget_link;
3215
+ }
3216
+
3217
+ WebView.postEvent('web_app_share_to_story', false, share_params);
3218
+ };
3219
+ WebApp.shareMessage = function (msg_id, callback) {
3220
+ if (!versionAtLeast('8.0')) {
3221
+ console.error('[Telegram.WebApp] Method shareMessage is not supported in version ' + webAppVersion);
3222
+ throw Error('WebAppMethodUnsupported');
3223
+ }
3224
+ if (WebAppShareMessageOpened) {
3225
+ console.error('[Telegram.WebApp] Share message is already opened');
3226
+ throw Error('WebAppShareMessageOpened');
3227
+ }
3228
+ WebAppShareMessageOpened = {
3229
+ callback: callback
3230
+ };
3231
+ WebView.postEvent('web_app_send_prepared_message', false, {id: msg_id});
3232
+ };
3233
+ WebApp.setEmojiStatus = function (custom_emoji_id, params, callback) {
3234
+ params = params || {};
3235
+ if (!versionAtLeast('8.0')) {
3236
+ console.error('[Telegram.WebApp] Method setEmojiStatus is not supported in version ' + webAppVersion);
3237
+ throw Error('WebAppMethodUnsupported');
3238
+ }
3239
+ var status_params = {};
3240
+ status_params.custom_emoji_id = custom_emoji_id;
3241
+ if (typeof params.duration !== 'undefined') {
3242
+ status_params.duration = params.duration;
3243
+ }
3244
+ if (WebAppEmojiStatusRequested) {
3245
+ console.error('[Telegram.WebApp] Emoji status is already requested');
3246
+ throw Error('WebAppEmojiStatusRequested');
3247
+ }
3248
+ WebAppEmojiStatusRequested = {
3249
+ callback: callback
3250
+ };
3251
+ WebView.postEvent('web_app_set_emoji_status', false, status_params);
3252
+ };
3253
+ WebApp.requestEmojiStatusAccess = function (callback) {
3254
+ if (!versionAtLeast('8.0')) {
3255
+ console.error('[Telegram.WebApp] Method requestEmojiStatusAccess is not supported in version ' + webAppVersion);
3256
+ throw Error('WebAppMethodUnsupported');
3257
+ }
3258
+ if (WebAppEmojiStatusAccessRequested) {
3259
+ console.error('[Telegram.WebApp] Emoji status permission is already requested');
3260
+ throw Error('WebAppEmojiStatusAccessRequested');
3261
+ }
3262
+ WebAppEmojiStatusAccessRequested = {
3263
+ callback: callback
3264
+ };
3265
+ WebView.postEvent('web_app_request_emoji_status_access');
3266
+ };
3267
+ WebApp.invokeCustomMethod = function (method, params, callback) {
3268
+ invokeCustomMethod(method, params, callback);
3269
+ };
3270
+ WebApp.hideKeyboard = function () {
3271
+ WebView.postEvent('web_app_hide_keyboard');
3272
+ };
3273
+ WebApp.ready = function () {
3274
+ WebView.postEvent('web_app_ready');
3275
+ };
3276
+ WebApp.expand = function () {
3277
+ WebView.postEvent('web_app_expand');
3278
+ };
3279
+ WebApp.close = function (options) {
3280
+ options = options || {};
3281
+ var req_params = {};
3282
+ if (versionAtLeast('7.6') && options.return_back) {
3283
+ req_params.return_back = true;
3284
+ }
3285
+ WebView.postEvent('web_app_close', false, req_params);
3286
+ };
3287
+
3288
+ window.Telegram.WebApp = WebApp;
3289
+
3290
+ updateHeaderColor();
3291
+ updateBackgroundColor();
3292
+ updateBottomBarColor();
3293
+ setViewportHeight();
3294
+ if (initParams.tgWebAppShowSettings) {
3295
+ SettingsButton.show();
3296
+ }
3297
+
3298
+ window.addEventListener('resize', onWindowResize);
3299
+ if (isIframe) {
3300
+ document.addEventListener('click', linkHandler);
3301
+ }
3302
+
3303
+ WebView.onEvent('theme_changed', onThemeChanged);
3304
+ WebView.onEvent('viewport_changed', onViewportChanged);
3305
+ WebView.onEvent('safe_area_changed', onSafeAreaChanged);
3306
+ WebView.onEvent('content_safe_area_changed', onContentSafeAreaChanged);
3307
+ WebView.onEvent('visibility_changed', onVisibilityChanged);
3308
+ WebView.onEvent('invoice_closed', onInvoiceClosed);
3309
+ WebView.onEvent('popup_closed', onPopupClosed);
3310
+ WebView.onEvent('qr_text_received', onQrTextReceived);
3311
+ WebView.onEvent('scan_qr_popup_closed', onScanQrPopupClosed);
3312
+ WebView.onEvent('clipboard_text_received', onClipboardTextReceived);
3313
+ WebView.onEvent('write_access_requested', onWriteAccessRequested);
3314
+ WebView.onEvent('phone_requested', onPhoneRequested);
3315
+ WebView.onEvent('file_download_requested', onFileDownloadRequested);
3316
+ WebView.onEvent('custom_method_invoked', onCustomMethodInvoked);
3317
+ WebView.onEvent('fullscreen_changed', onFullscreenChanged);
3318
+ WebView.onEvent('fullscreen_failed', onFullscreenFailed);
3319
+ WebView.onEvent('home_screen_added', onHomeScreenAdded);
3320
+ WebView.onEvent('home_screen_checked', onHomeScreenChecked);
3321
+ WebView.onEvent('prepared_message_sent', onPreparedMessageSent);
3322
+ WebView.onEvent('prepared_message_failed', onPreparedMessageFailed);
3323
+ WebView.onEvent('emoji_status_set', onEmojiStatusSet);
3324
+ WebView.onEvent('emoji_status_failed', onEmojiStatusFailed);
3325
+ WebView.onEvent('emoji_status_access_requested', onEmojiStatusAccessRequested);
3326
+ WebView.postEvent('web_app_request_theme');
3327
+ WebView.postEvent('web_app_request_viewport');
3328
+ WebView.postEvent('web_app_request_safe_area');
3329
+ WebView.postEvent('web_app_request_content_safe_area');
3330
+
3331
+ })();