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 invali
1292d', 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 invali
1440d', 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 invali
2293d', 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 invali
2858d', 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 invali
3019d', 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})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.