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