Created
August 27, 2024 13:46
-
-
Save Notookk/e40b076ce4640ca09bf4250ad54337a0 to your computer and use it in GitHub Desktop.
try_to_make
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let queuedSongs = []; | |
let ConnectedUsers = [] | |
let isPaused = false; | |
function formatTime(seconds) { | |
const hours = Math.floor(seconds / 3600); | |
const minutes = Math.floor((seconds % 3600) / 60); | |
const remainingSeconds = Math.floor(seconds % 60); | |
if (hours > 0) { | |
return `${hours}:${minutes < 10 ? '0' : ''}${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`; | |
} else { | |
return `${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`; | |
} | |
} | |
const styleElem = document.createElement('style'); | |
document.head.appendChild(styleElem); | |
function changeSong(data) { | |
console.log('Changing song to:', data); | |
if (isStarted === true) { | |
player.pause() | |
} | |
if (data === 'None') { | |
document.getElementById('loader').style.display = 'none'; | |
document.getElementById('main-container').style.display = 'none'; | |
document.getElementById('no-song').style.display = 'flex'; | |
return; | |
} | |
isStarted = true; | |
document.getElementById('loader').style.display = 'flex'; | |
document.getElementById('no-song').style.display = 'none'; | |
document.getElementById('main-container').style.display = 'none'; | |
const videoid = data['videoid'] | |
const title = data['title'] | |
const file_url = data['file']; | |
isPaused = data['paused'] | |
time_elapsed = data['time_elapsed']; | |
response_time = data['response_time']; | |
// Change the song data on the page | |
document.getElementById('song-title').innerHTML = title; | |
const imageUrl = `https://mainmusic.4.213.40.172.sslip.io/yt_img/${videoid}/max`; | |
document.getElementById('bg-image').src = imageUrl | |
styleElem.innerHTML = ` | |
.overlay-img:after { | |
background: url('${imageUrl}') no-repeat center/cover; | |
} | |
.bg-container{ | |
background: linear-gradient(to bottom, transparent 0%, var(--background-color) 100%), url('${imageUrl}') no-repeat center/cover; | |
}` | |
// Set the audio element source | |
const audioElement = document.getElementById('player'); | |
audioElement.src = file_url; | |
audioElement.load(); | |
document.getElementById('loader').style.display = 'none'; | |
document.getElementById('main-container').style.display = 'flex'; | |
} | |
function updateQueueList() { | |
if (queuedSongs.length === 0) { | |
document.getElementById('queue-tab').innerHTML = `Queue`; | |
document.getElementById('song-list').innerHTML = `<p class="info">No Queued Songs</p>`; | |
console.log('Queue is empty'); | |
return; | |
} | |
console.log('Updating queue:', queuedSongs); | |
document.getElementById('queue-tab').innerHTML = `Queue (${queuedSongs.length} Songs)`; | |
let html = '' | |
for (let i = 0; i < queuedSongs.length; i++) { | |
const song = queuedSongs[i]; | |
const title = song['title']; | |
let duration = '0:00'; | |
if (song['duration'].toString().includes(':')) { | |
// If the duration is in minutes:seconds format | |
duration = song['duration'] | |
} | |
else { | |
// If the duration is in seconds, convert it to minutes:seconds | |
duration = formatTime(song['duration']); | |
} | |
const videoid = song['videoid']; | |
html += `<div class="song-item"> | |
<div class="song-img" style="background: url('https://mainmusic.4.213.40.172.sslip.io/yt_img/${videoid}/min') no-repeat center/cover;"> | |
</div> | |
<div class="queue-name"> | |
<p>${title}</p> | |
<p class="time-p">${duration}</p> | |
</div> | |
</div>` | |
} | |
document.getElementById('song-list').innerHTML = html; | |
} | |
function updateUsersList() { | |
console.log('Updating Users List:', ConnectedUsers); | |
const addedUsers = []; | |
let html = ''; | |
ConnectedUsers.forEach(user => { | |
const id = user[0]; | |
let name = user[2]; | |
let imgUrl; | |
if (!addedUsers.includes(id)) { | |
addedUsers.push(id); | |
if (id === currentUserID) { | |
name += ' (You)'; | |
} | |
imgUrl = user[1] === 'None' | |
? 'https://mainmusic.4.213.40.172.sslip.io/static/default-profile-photo.jpg' | |
: `https://mainmusic.4.213.40.172.sslip.io/user_img/${id}.jpg`; | |
html += ` | |
<div class="song-item"> | |
<div class="song-img" style="background: url('${imgUrl}') no-repeat center/cover;"></div> | |
<div class="queue-name"> | |
<p>${name}</p> | |
</div> | |
</div>`; | |
} | |
}); | |
document.getElementById('user-list').innerHTML = html; | |
document.getElementById('users-tab').innerHTML = `Users (${addedUsers.length})`; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<!-- Mirrored from mainmusic.4.213.40.172.sslip.io/static/index.html by HTTrack Website Copier/3.x [XR&CO'2014], Mon, 26 Aug 2024 07:45:08 GMT --> | |
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=utf-8" /><!-- /Added by HTTrack --> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>TechZMusic</title> | |
<!-- Audio Player --> | |
<link rel="stylesheet" href="../../cdn.plyr.io/3.7.8/plyr.css" /> | |
<script src="../../cdn.plyr.io/3.7.8/plyr.polyfilled.js"></script> | |
<!-- Font --> | |
<link rel="preconnect" href="https://fonts.googleapis.com/" /> | |
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin /> | |
<link | |
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" | |
rel="stylesheet" /> | |
<!-- External Scripts --> | |
<script src="../../cdn.socket.io/4.7.5/socket.io.min.js"></script> | |
<script src="../../telegram.org/js/telegram-web-app.js"></script> | |
<!-- Project Code --> | |
<link rel="stylesheet" href="style1b3b.css?v=63" /> | |
<script src="extra1b3b.js?v=63"></script> | |
<script src="socket_io1b3b.js?v=63"></script> | |
<script src="script1b3b.js?v=63"></script> | |
<script src="telegram1b3b.js?v=63"></script> | |
</head> | |
<body> | |
<div id="join-div" class="join-div" style="display: flex"> | |
<button id="join-btn" class="glow-button">Join Group Music</button> | |
</div> | |
<div id="loader" class="loader" style="display: none"> | |
<img src="load.gif" alt="Loading..." height="100px" width="100px" /> | |
</div> | |
<div id="no-song" class="container" style="display: none"> | |
<h3>No Song Is Playing Currently, Use /play CMD</h3> | |
</div> | |
<div id="main-container" class="main-container" style="display: none"> | |
<div id="player-div"> | |
<div id="bg-container" class="bg-container"> | |
<img id="bg-image" src="#" /> | |
</div> | |
<div class="overlay-container"> | |
<div id="overlay-img" class="overlay-img"></div> | |
<div id="song-details" class="song-details"> | |
<p id="song-title" class="title"></p> | |
<audio id="player"> | |
Your browser does not support the audio element. | |
</audio> | |
<div class="time-div"> | |
<p id="current-time"></p> | |
<p id="total-time"></p> | |
</div> | |
</div> | |
<!-- Tabs for switching between Queue and Connected Users --> | |
<div class="tab-div"> | |
<div id="users-tab" class="tab-button active-tab">Users</div> | |
<div id="queue-tab" class="tab-button">Queue</div> | |
</div> | |
<div id="queue-div" class="queue-div" style="display: none;"> | |
<div id="song-list" class="song-list"> | |
</div> | |
</div> | |
<div id="users-div" class="users-div queue-div"> | |
<div id="user-list" class="user-list song-list"> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</body> | |
<!-- Mirrored from mainmusic.4.213.40.172.sslip.io/static/index.html by HTTrack Website Copier/3.x [XR&CO'2014], Mon, 26 Aug 2024 07:45:15 GMT --> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let time_elapsed = 0; | |
let response_time = 0; | |
let player | |
let isStarted = false; | |
let currentUserID | |
function InitWebsite(user_id, group_id) { | |
currentUserID = user_id | |
player = new Plyr('#player', { | |
controls: [ | |
'progress', // The progress bar and scrubber for playback and buffering | |
] | |
}); | |
const audioElement = document.getElementById('player') | |
audioElement.src = 'no-sound.mp3'; | |
audioElement.load(); | |
player.on('timeupdate', () => { | |
const currentTime = player.currentTime; | |
document.getElementById('current-time').innerHTML = formatTime(currentTime); | |
}); | |
player.on('loadedmetadata', () => { | |
if (isStarted === true) { | |
const totalTime = player.duration; | |
document.getElementById('total-time').innerHTML = formatTime(totalTime); | |
if (isPaused === true) { | |
player.pause() | |
} | |
else { | |
player.play() | |
} | |
const time_spent_on_response = new Date().getTime() - response_time; // in milliseconds | |
player.currentTime = time_elapsed + time_spent_on_response / 1000; | |
} | |
else { | |
// running no-sound.mp3 | |
player.play() | |
} | |
}); | |
initSocket(user_id, group_id, telegram.initData); | |
} | |
addEventListener( | |
'DOMContentLoaded', | |
() => { | |
document.getElementById('queue-tab').addEventListener('click', () => { | |
document.getElementById('queue-tab').classList.add('active-tab'); | |
document.getElementById('users-tab').classList.remove('active-tab'); | |
document.getElementById('queue-div').style.display = 'flex'; | |
document.getElementById('users-div').style.display = 'none'; | |
}); | |
document.getElementById('users-tab').addEventListener('click', () => { | |
document.getElementById('users-tab').classList.add('active-tab'); | |
document.getElementById('queue-tab').classList.remove('active-tab'); | |
document.getElementById('users-div').style.display = 'flex'; | |
document.getElementById('queue-div').style.display = 'none'; | |
}); | |
} | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function initSocket(user_id, group_id, init_data) { | |
const socket = io('https://mainmusic.4.213.40.172.sslip.io', { | |
transports: ['websocket'], | |
path: '/ws/socket.io', query: { 'user_id': user_id, 'group_id': group_id } | |
}); | |
socket.on('connect', () => { | |
console.log('Connected to server'); | |
socket.emit('verify_user', init_data); | |
}); | |
socket.on('change_song', (data) => { | |
changeSong(data); | |
}); | |
socket.on('skip_songs', (no_of_skips) => { | |
for (let i = 0; i < no_of_skips; i++) { | |
queuedSongs.shift(); | |
} | |
updateQueueList(); | |
}); | |
socket.on('disconnect', () => { | |
console.log('Disconnected from server'); | |
}); | |
socket.on('add_to_queue', (data) => { | |
console.log('Adding song to queue'); | |
console.log(data); | |
for (let song of data) { | |
queuedSongs.push(song); | |
} | |
updateQueueList(); | |
}); | |
socket.on('shuffle_queue', (data) => { | |
console.log('Shuffling queue'); | |
console.log(data); | |
queuedSongs = data; | |
updateQueueList(); | |
}); | |
socket.on('add_users_list', (data) => { | |
console.log('Adding users to list'); | |
console.log(data); | |
for (let user of data) { | |
ConnectedUsers.push(user); | |
} | |
updateUsersList(); | |
}); | |
socket.on('remove_users_list', (data) => { | |
console.log('Removing user from list'); | |
console.log(data); | |
for (let i = 0; i < ConnectedUsers.length; i++) { | |
if (ConnectedUsers[i][0] === data) { | |
ConnectedUsers.splice(i, 1); | |
break; | |
} | |
} | |
updateUsersList(); | |
}); | |
socket.on('pause_song', () => { | |
isPaused = true | |
player.pause(); | |
}); | |
socket.on('resume_song', () => { | |
isPaused = false | |
player.play(); | |
}); | |
socket.on('force_exit', () => { | |
window.Telegram.WebApp.close(); | |
}); | |
socket.on('seek_song', (data) => { | |
const time_spent_on_response = new Date().getTime() - data['response_time']; // in milliseconds | |
player.currentTime = data['time_elapsed'] + time_spent_on_response / 1000; | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:root { | |
--background-color: #000813; | |
--plyr-audio-controls-background: none; | |
--plyr-control-spacing: 0px; | |
--overlay-img-size: calc(min(200px, 50vw)); | |
--overlay-translate-y: calc(-0.8 * var(--overlay-img-size)); | |
} | |
* { | |
box-sizing: border-box; | |
margin: 0; | |
padding: 0; | |
font-family: "Roboto", sans-serif; | |
font-style: normal; | |
} | |
body { | |
font-family: Arial, sans-serif; | |
background-color: var(--background-color); | |
display: flex; | |
justify-content: start; | |
align-items: center; | |
height: 100dvh; | |
width: 100dvw; | |
margin: 0; | |
color: #fff; | |
overflow-x: hidden; | |
flex-direction: column; | |
} | |
.header { | |
width: 100%; | |
display: flex; | |
justify-content: end; | |
align-items: center; | |
} | |
.tg-icon { | |
width: 45px; | |
height: 45px; | |
margin-right: 10px; | |
margin-top: 10px; | |
border-radius: 50%; | |
overflow: hidden; | |
border: 2px solid #fff; | |
padding: 2px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.tg-icon img { | |
width: 100%; | |
height: 100%; | |
border-radius: 50%; | |
} | |
/* Gradient Glow Border Btn Start */ | |
.glow-button { | |
border: none; | |
outline: none; | |
color: #fff; | |
background: #111; | |
cursor: pointer; | |
position: relative; | |
z-index: 0; | |
border-radius: 10px; | |
} | |
.glow-button:before { | |
content: ''; | |
background: linear-gradient(45deg, #ff0000, #ff7300, #fffb00, #48ff00, #00ffd5, #002bff, #7a00ff, #ff00c8, #ff0000); | |
position: absolute; | |
top: -2px; | |
left: -2px; | |
background-size: 400%; | |
z-index: -1; | |
filter: blur(5px); | |
width: calc(100% + 4px); | |
height: calc(100% + 4px); | |
animation: glowing 20s linear infinite; | |
opacity: 0; | |
transition: opacity .3s ease-in-out; | |
border-radius: 10px; | |
} | |
.glow-button:active { | |
color: #000 | |
} | |
.glow-button:active:after { | |
background: transparent; | |
} | |
.glow-button:before { | |
opacity: 1; | |
} | |
.glow-button:after { | |
z-index: -1; | |
content: ''; | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
background: #111; | |
left: 0; | |
top: 0; | |
border-radius: 10px; | |
} | |
@keyframes glowing { | |
0% { | |
background-position: 0 0; | |
} | |
50% { | |
background-position: 400% 0; | |
} | |
100% { | |
background-position: 0 0; | |
} | |
} | |
/* Gradient Glow Border Btn End */ | |
.join-div { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
width: 100%; | |
padding: 0px 20px; | |
padding-top: 100px; | |
flex-direction: column; | |
} | |
#join-btn { | |
width: 220px; | |
height: 50px; | |
color: white; | |
padding: 10px 20px; | |
border: none; | |
cursor: pointer; | |
font-size: 16px; | |
font-weight: 500; | |
transition: 0.3s; | |
} | |
#join-btn:hover { | |
transform: scale(1.05); | |
} | |
#no-song { | |
padding-top: 100px; | |
} | |
.loader { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
width: 100%; | |
padding-top: 100px; | |
} | |
.loader img { | |
max-width: 100px; | |
max-height: 100px; | |
width: 50vw; | |
height: 50vw; | |
} | |
.container { | |
padding: 20px; | |
text-align: center; | |
width: 100%; | |
max-width: 400px; | |
display: flex; | |
justify-content: start; | |
align-items: center; | |
flex-direction: column; | |
} | |
.container h3 { | |
font-size: clamp(1.4rem, 3vw, 2rem); | |
margin-bottom: 20px; | |
font-weight: bold; | |
text-align: center; | |
width: 100% | |
} | |
.container img { | |
border-radius: 10px; | |
width: 100%; | |
} | |
.container h2 { | |
font-size: clamp(1rem, 2.5vw, 1.2rem); | |
margin: 15px 0px; | |
font-weight: 700; | |
text-align: left; | |
width: 100%; | |
} | |
/* New Css */ | |
/* Main Container */ | |
.main-container { | |
width: 100%; | |
height: 100%; | |
display: flex; | |
justify-content: start; | |
align-items: center; | |
flex-direction: column; | |
max-width: 400px; | |
} | |
#player-div { | |
width: 100%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
flex-direction: column; | |
opacity: 1; | |
transition: opacity 0.5s; | |
} | |
.bg-container { | |
width: 100%; | |
filter: blur(5px); | |
max-height: var(--overlay-img-size); | |
} | |
.bg-container img { | |
width: 100%; | |
opacity: 0; | |
} | |
.overlay-container { | |
transform: translateY(var(--overlay-translate-y)); | |
position: relative; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
flex-direction: column; | |
width: 100%; | |
max-width: 400px; | |
} | |
.overlay-img { | |
width: var(--overlay-img-size); | |
height: var(--overlay-img-size); | |
border-radius: 50%; | |
border: 2px solid #fff; | |
z-index: 3; | |
position: relative; | |
} | |
.overlay-img:before { | |
background: linear-gradient(45deg, #ff0000, #ff7300, #fffb00, #48ff00, #00ffd5, #002bff, #7a00ff, #ff00c8, #ff0000); | |
content: ''; | |
position: absolute; | |
top: -2px; | |
left: -2px; | |
background-size: 400%; | |
z-index: -1; | |
filter: blur(5px); | |
width: calc(100% + 4px); | |
height: calc(100% + 4px); | |
animation: glowing 20s linear infinite; | |
opacity: 1; | |
transition: opacity .3s ease-in-out; | |
border-radius: 50%; | |
} | |
.overlay-img:after { | |
z-index: -1; | |
content: ''; | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
left: 0; | |
top: 0; | |
border-radius: 50%; | |
} | |
.main-container .song-details { | |
padding: 0px 20px; | |
text-align: center; | |
width: 100%; | |
max-width: 400px; | |
z-index: 5; | |
margin-top: 20px; | |
} | |
.main-container .song-details .title { | |
font-size: clamp(1rem, 2.5vw, 1.2rem); | |
font-weight: 700; | |
margin-bottom: 20px; | |
display: -webkit-box; | |
line-clamp: 2; | |
-webkit-line-clamp: 2; | |
-webkit-box-orient: vertical; | |
overflow: hidden; | |
} | |
.plyr { | |
width: 100%; | |
} | |
.plyr__progress { | |
pointer-events: none; | |
} | |
.time-div { | |
display: flex; | |
justify-content: space-between; | |
width: 100%; | |
} | |
.time-div p { | |
font-size: clamp(0.8rem, 3vw, 1rem); | |
font-weight: 500; | |
color: #ccc; | |
} | |
.queue-div { | |
margin-top: 20px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
width: 100%; | |
flex-direction: column; | |
max-width: 400px; | |
padding: 0px 10px; | |
} | |
.queue-div .queue-header { | |
font-size: clamp(1rem, 2.5vw, 1.2rem); | |
font-weight: 700; | |
margin-bottom: 10px; | |
text-align: left; | |
width: 100%; | |
} | |
.queue-div .song-list { | |
width: 100%; | |
display: flex; | |
justify-content: start; | |
align-items: center; | |
flex-direction: column; | |
} | |
.queue-div .song-list .song-item { | |
display: flex; | |
justify-content: start; | |
align-items: center; | |
width: 100%; | |
padding: 10px 0px; | |
border-bottom: 2px solid #333; | |
} | |
.queue-div .song-img { | |
width: 40px; | |
height: 40px; | |
margin-right: 10px; | |
border-radius: 15%; | |
} | |
.queue-div .info { | |
width: 100%; | |
text-align: center; | |
margin-top: 20px; | |
} | |
.queue-div .queue-name { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
width: calc(100% - 50px); | |
} | |
.queue-div p { | |
font-size: clamp(0.9rem, 2.5vw, 1rem); | |
font-weight: 500; | |
color: #ccc; | |
display: -webkit-box; | |
line-clamp: 2; | |
-webkit-line-clamp: 2; | |
-webkit-box-orient: vertical; | |
overflow: hidden; | |
width: 100%; | |
} | |
.queue-div .time-p { | |
width: 80px; | |
text-align: right; | |
} | |
.users-div .song-img { | |
border-radius: 50%; | |
border: 1px solid #fff; | |
} | |
/* Container for tab buttons */ | |
.tab-div { | |
display: flex; | |
justify-content: start; | |
align-items: center; | |
width: 100%; | |
margin-top: 40px; | |
max-width: 400px; | |
gap: 10px; | |
padding: 0px 10px; | |
} | |
/* Style for each tab button */ | |
.tab-button { | |
text-align: center; | |
width: calc(50% - 10px); | |
padding: 8px 0px; | |
border: 2px solid transparent; | |
background: linear-gradient(135deg, #2c3e50, #34495e); | |
color: white; | |
font-size: 16px; | |
cursor: pointer; | |
transition: all 0.5s ease; | |
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); | |
border-radius: 8px; | |
} | |
.tab-button:hover { | |
background: linear-gradient(135deg, #34495e, #2c3e50); | |
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); | |
transform: scale(1.05); | |
} | |
.tab-button.active-tab { | |
border-color: #4a90e2; | |
background: #1c2833; | |
color: #4a90e2; | |
font-weight: bold; | |
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// WebView | |
(function () { | |
var eventHandlers = {}; | |
var locationHash = ''; | |
try { | |
locationHash = location.hash.toString(); | |
} catch (e) {} | |
var initParams = urlParseHashParams(locationHash); | |
var storedParams = sessionStorageGet('initParams'); | |
if (storedParams) { | |
for (var key in storedParams) { | |
if (typeof initParams[key] === 'undefined') { | |
initParams[key] = storedParams[key]; | |
} | |
} | |
} | |
sessionStorageSet('initParams', initParams); | |
var isIframe = false, iFrameStyle; | |
try { | |
isIframe = (window.parent != null && window != window.parent); | |
if (isIframe) { | |
window.addEventListener('message', function (event) { | |
if (event.source !== window.parent) return; | |
try { | |
var dataParsed = JSON.parse(event.data); | |
} catch (e) { | |
return; | |
} | |
if (!dataParsed || !dataParsed.eventType) { | |
return; | |
} | |
if (dataParsed.eventType == 'set_custom_style') { | |
if (event.origin === 'https://web.telegram.org') { | |
iFrameStyle.innerHTML = dataParsed.eventData; | |
} | |
} else if (dataParsed.eventType == 'reload_iframe') { | |
try { | |
window.parent.postMessage(JSON.stringify({eventType: 'iframe_will_reload'}), '*'); | |
} catch (e) {} | |
location.reload(); | |
} else { | |
receiveEvent(dataParsed.eventType, dataParsed.eventData); | |
} | |
}); | |
iFrameStyle = document.createElement('style'); | |
document.head.appendChild(iFrameStyle); | |
try { | |
window.parent.postMessage(JSON.stringify({eventType: 'iframe_ready', eventData: {reload_supported: true}}), '*'); | |
} catch (e) {} | |
} | |
} catch (e) {} | |
function urlSafeDecode(urlencoded) { | |
try { | |
urlencoded = urlencoded.replace(/\+/g, '%20'); | |
return decodeURIComponent(urlencoded); | |
} catch (e) { | |
return urlencoded; | |
} | |
} | |
function urlParseHashParams(locationHash) { | |
locationHash = locationHash.replace(/^#/, ''); | |
var params = {}; | |
if (!locationHash.length) { | |
return params; | |
} | |
if (locationHash.indexOf('=') < 0 && locationHash.indexOf('?') < 0) { | |
params._path = urlSafeDecode(locationHash); | |
return params; | |
} | |
var qIndex = locationHash.indexOf('?'); | |
if (qIndex >= 0) { | |
var pathParam = locationHash.substr(0, qIndex); | |
params._path = urlSafeDecode(pathParam); | |
locationHash = locationHash.substr(qIndex + 1); | |
} | |
var query_params = urlParseQueryString(locationHash); | |
for (var k in query_params) { | |
params[k] = query_params[k]; | |
} | |
return params; | |
} | |
function urlParseQueryString(queryString) { | |
var params = {}; | |
if (!queryString.length) { | |
return params; | |
} | |
var queryStringParams = queryString.split('&'); | |
var i, param, paramName, paramValue; | |
for (i = 0; i < queryStringParams.length; i++) { | |
param = queryStringParams[i].split('='); | |
paramName = urlSafeDecode(param[0]); | |
paramValue = param[1] == null ? null : urlSafeDecode(param[1]); | |
params[paramName] = paramValue; | |
} | |
return params; | |
} | |
// Telegram apps will implement this logic to add service params (e.g. tgShareScoreUrl) to game URL | |
function urlAppendHashParams(url, addHash) { | |
// url looks like 'https://game.com/path?query=1#hash' | |
// addHash looks like 'tgShareScoreUrl=' + encodeURIComponent('tgb://share_game_score?hash=very_long_hash123') | |
var ind = url.indexOf('#'); | |
if (ind < 0) { | |
// https://game.com/path -> https://game.com/path#tgShareScoreUrl=etc | |
return url + '#' + addHash; | |
} | |
var curHash = url.substr(ind + 1); | |
if (curHash.indexOf('=') >= 0 || curHash.indexOf('?') >= 0) { | |
// https://game.com/#hash=1 -> https://game.com/#hash=1&tgShareScoreUrl=etc | |
// https://game.com/#path?query -> https://game.com/#path?query&tgShareScoreUrl=etc | |
return url + '&' + addHash; | |
} | |
// https://game.com/#hash -> https://game.com/#hash?tgShareScoreUrl=etc | |
if (curHash.length > 0) { | |
return url + '?' + addHash; | |
} | |
// https://game.com/# -> https://game.com/#tgShareScoreUrl=etc | |
return url + addHash; | |
} | |
function postEvent(eventType, callback, eventData) { | |
if (!callback) { | |
callback = function () {}; | |
} | |
if (eventData === undefined) { | |
eventData = ''; | |
} | |
console.log('[Telegram.WebView] > postEvent', eventType, eventData); | |
if (window.TelegramWebviewProxy !== undefined) { | |
TelegramWebviewProxy.postEvent(eventType, JSON.stringify(eventData)); | |
callback(); | |
} | |
else if (window.external && 'notify' in window.external) { | |
window.external.notify(JSON.stringify({eventType: eventType, eventData: eventData})); | |
callback(); | |
} | |
else if (isIframe) { | |
try { | |
var trustedTarget = 'https://web.telegram.org'; | |
// For now we don't restrict target, for testing purposes | |
trustedTarget = '*'; | |
window.parent.postMessage(JSON.stringify({eventType: eventType, eventData: eventData}), trustedTarget); | |
callback(); | |
} catch (e) { | |
callback(e); | |
} | |
} | |
else { | |
callback({notAvailable: true}); | |
} | |
}; | |
function receiveEvent(eventType, eventData) { | |
console.log('[Telegram.WebView] < receiveEvent', eventType, eventData); | |
callEventCallbacks(eventType, function(callback) { | |
callback(eventType, eventData); | |
}); | |
} | |
function callEventCallbacks(eventType, func) { | |
var curEventHandlers = eventHandlers[eventType]; | |
if (curEventHandlers === undefined || | |
!curEventHandlers.length) { | |
return; | |
} | |
for (var i = 0; i < curEventHandlers.length; i++) { | |
try { | |
func(curEventHandlers[i]); | |
} catch (e) {} | |
} | |
} | |
function onEvent(eventType, callback) { | |
if (eventHandlers[eventType] === undefined) { | |
eventHandlers[eventType] = []; | |
} | |
var index = eventHandlers[eventType].indexOf(callback); | |
if (index === -1) { | |
eventHandlers[eventType].push(callback); | |
} | |
}; | |
function offEvent(eventType, callback) { | |
if (eventHandlers[eventType] === undefined) { | |
return; | |
} | |
var index = eventHandlers[eventType].indexOf(callback); | |
if (index === -1) { | |
return; | |
} | |
eventHandlers[eventType].splice(index, 1); | |
}; | |
function openProtoUrl(url) { | |
if (!url.match(/^(web\+)?tgb?:\/\/./)) { | |
return false; | |
} | |
var useIframe = navigator.userAgent.match(/iOS|iPhone OS|iPhone|iPod|iPad/i) ? true : false; | |
if (useIframe) { | |
var iframeContEl = document.getElementById('tgme_frame_cont') || document.body; | |
var iframeEl = document.createElement('iframe'); | |
iframeContEl.appendChild(iframeEl); | |
var pageHidden = false; | |
var enableHidden = function () { | |
pageHidden = true; | |
}; | |
window.addEventListener('pagehide', enableHidden, false); | |
window.addEventListener('blur', enableHidden, false); | |
if (iframeEl !== null) { | |
iframeEl.src = url; | |
} | |
setTimeout(function() { | |
if (!pageHidden) { | |
window.location = url; | |
} | |
window.removeEventListener('pagehide', enableHidden, false); | |
window.removeEventListener('blur', enableHidden, false); | |
}, 2000); | |
} | |
else { | |
window.location = url; | |
} | |
return true; | |
} | |
function sessionStorageSet(key, value) { | |
try { | |
window.sessionStorage.setItem('__telegram__' + key, JSON.stringify(value)); | |
return true; | |
} catch(e) {} | |
return false; | |
} | |
function sessionStorageGet(key) { | |
try { | |
return JSON.parse(window.sessionStorage.getItem('__telegram__' + key)); | |
} catch(e) {} | |
return null; | |
} | |
if (!window.Telegram) { | |
window.Telegram = {}; | |
} | |
window.Telegram.WebView = { | |
initParams: initParams, | |
isIframe: isIframe, | |
onEvent: onEvent, | |
offEvent: offEvent, | |
postEvent: postEvent, | |
receiveEvent: receiveEvent, | |
callEventCallbacks: callEventCallbacks | |
}; | |
window.Telegram.Utils = { | |
urlSafeDecode: urlSafeDecode, | |
urlParseQueryString: urlParseQueryString, | |
urlParseHashParams: urlParseHashParams, | |
urlAppendHashParams: urlAppendHashParams, | |
sessionStorageSet: sessionStorageSet, | |
sessionStorageGet: sessionStorageGet | |
}; | |
// For Windows Phone app | |
window.TelegramGameProxy_receiveEvent = receiveEvent; | |
// App backward compatibility | |
window.TelegramGameProxy = { | |
receiveEvent: receiveEvent | |
}; | |
})(); | |
// WebApp | |
(function () { | |
var Utils = window.Telegram.Utils; | |
var WebView = window.Telegram.WebView; | |
var initParams = WebView.initParams; | |
var isIframe = WebView.isIframe; | |
var WebApp = {}; | |
var webAppInitData = '', webAppInitDataUnsafe = {}; | |
var themeParams = {}, colorScheme = 'light'; | |
var webAppVersion = '6.0'; | |
var webAppPlatform = 'unknown'; | |
if (initParams.tgWebAppData && initParams.tgWebAppData.length) { | |
webAppInitData = initParams.tgWebAppData; | |
webAppInitDataUnsafe = Utils.urlParseQueryString(webAppInitData); | |
for (var key in webAppInitDataUnsafe) { | |
var val = webAppInitDataUnsafe[key]; | |
try { | |
if (val.substr(0, 1) == '{' && val.substr(-1) == '}' || | |
val.substr(0, 1) == '[' && val.substr(-1) == ']') { | |
webAppInitDataUnsafe[key] = JSON.parse(val); | |
} | |
} catch (e) {} | |
} | |
} | |
if (initParams.tgWebAppThemeParams && initParams.tgWebAppThemeParams.length) { | |
var themeParamsRaw = initParams.tgWebAppThemeParams; | |
try { | |
var theme_params = JSON.parse(themeParamsRaw); | |
if (theme_params) { | |
setThemeParams(theme_params); | |
} | |
} catch (e) {} | |
} | |
var theme_params = Utils.sessionStorageGet('themeParams'); | |
if (theme_params) { | |
setThemeParams(theme_params); | |
} | |
if (initParams.tgWebAppVersion) { | |
webAppVersion = initParams.tgWebAppVersion; | |
} | |
if (initParams.tgWebAppPlatform) { | |
webAppPlatform = initParams.tgWebAppPlatform; | |
} | |
function onThemeChanged(eventType, eventData) { | |
if (eventData.theme_params) { | |
setThemeParams(eventData.theme_params); | |
window.Telegram.WebApp.MainButton.setParams({}); | |
updateBackgroundColor(); | |
receiveWebViewEvent('themeChanged'); | |
} | |
} | |
var lastWindowHeight = window.innerHeight; | |
function onViewportChanged(eventType, eventData) { | |
if (eventData.height) { | |
window.removeEventListener('resize', onWindowResize); | |
setViewportHeight(eventData); | |
} | |
} | |
function onWindowResize(e) { | |
if (lastWindowHeight != window.innerHeight) { | |
lastWindowHeight = window.innerHeight; | |
receiveWebViewEvent('viewportChanged', { | |
isStateStable: true | |
}); | |
} | |
} | |
function linkHandler(e) { | |
if (e.metaKey || e.ctrlKey) return; | |
var el = e.target; | |
while (el.tagName != 'A' && el.parentNode) { | |
el = el.parentNode; | |
} | |
if (el.tagName == 'A' && | |
el.target != '_blank' && | |
(el.protocol == 'http:' || el.protocol == 'https:') && | |
el.hostname == 't.me') { | |
WebApp.openTgLink(el.href); | |
e.preventDefault(); | |
} | |
} | |
function strTrim(str) { | |
return str.toString().replace(/^\s+|\s+$/g, ''); | |
} | |
function receiveWebViewEvent(eventType) { | |
var args = Array.prototype.slice.call(arguments); | |
eventType = args.shift(); | |
WebView.callEventCallbacks('webview:' + eventType, function(callback) { | |
callback.apply(WebApp, args); | |
}); | |
} | |
function onWebViewEvent(eventType, callback) { | |
WebView.onEvent('webview:' + eventType, callback); | |
}; | |
function offWebViewEvent(eventType, callback) { | |
WebView.offEvent('webview:' + eventType, callback); | |
}; | |
function setCssProperty(name, value) { | |
var root = document.documentElement; | |
if (root && root.style && root.style.setProperty) { | |
root.style.setProperty('--tg-' + name, value); | |
} | |
} | |
function setThemeParams(theme_params) { | |
// temp iOS fix | |
if (theme_params.bg_color == '#1c1c1d' && | |
theme_params.bg_color == theme_params.secondary_bg_color) { | |
theme_params.secondary_bg_color = '#2c2c2e'; | |
} | |
var color; | |
for (var key in theme_params) { | |
if (color = parseColorToHex(theme_params[key])) { | |
themeParams[key] = color; | |
if (key == 'bg_color') { | |
colorScheme = isColorDark(color) ? 'dark' : 'light' | |
setCssProperty('color-scheme', colorScheme); | |
} | |
key = 'theme-' + key.split('_').join('-'); | |
setCssProperty(key, color); | |
} | |
} | |
Utils.sessionStorageSet('themeParams', themeParams); | |
} | |
var webAppCallbacks = {}; | |
function generateCallbackId(len) { | |
var tries = 100; | |
while (--tries) { | |
var id = '', chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', chars_len = chars.length; | |
for (var i = 0; i < len; i++) { | |
id += chars[Math.floor(Math.random() * chars_len)]; | |
} | |
if (!webAppCallbacks[id]) { | |
webAppCallbacks[id] = {}; | |
return id; | |
} | |
} | |
throw Error('WebAppCallbackIdGenerateFailed'); | |
} | |
var viewportHeight = false, viewportStableHeight = false, isExpanded = true; | |
function setViewportHeight(data) { | |
if (typeof data !== 'undefined') { | |
isExpanded = !!data.is_expanded; | |
viewportHeight = data.height; | |
if (data.is_state_stable) { | |
viewportStableHeight = data.height; | |
} | |
receiveWebViewEvent('viewportChanged', { | |
isStateStable: !!data.is_state_stable | |
}); | |
} | |
var height, stable_height; | |
if (viewportHeight !== false) { | |
height = (viewportHeight - mainButtonHeight) + 'px'; | |
} else { | |
height = mainButtonHeight ? 'calc(100vh - ' + mainButtonHeight + 'px)' : '100vh'; | |
} | |
if (viewportStableHeight !== false) { | |
stable_height = (viewportStableHeight - mainButtonHeight) + 'px'; | |
} else { | |
stable_height = mainButtonHeight ? 'calc(100vh - ' + mainButtonHeight + 'px)' : '100vh'; | |
} | |
setCssProperty('viewport-height', height); | |
setCssProperty('viewport-stable-height', stable_height); | |
} | |
var isClosingConfirmationEnabled = false; | |
function setClosingConfirmation(need_confirmation) { | |
if (!versionAtLeast('6.2')) { | |
console.warn('[Telegram.WebApp] Closing confirmation is not supported in version ' + webAppVersion); | |
return; | |
} | |
isClosingConfirmationEnabled = !!need_confirmation; | |
WebView.postEvent('web_app_setup_closing_behavior', false, {need_confirmation: isClosingConfirmationEnabled}); | |
} | |
var isVerticalSwipesEnabled = true; | |
function toggleVerticalSwipes(enable_swipes) { | |
if (!versionAtLeast('7.7')) { | |
console.warn('[Telegram.WebApp] Changing swipes behavior is not supported in version ' + webAppVersion); | |
return; | |
} | |
isVerticalSwipesEnabled = !!enable_swipes; | |
WebView.postEvent('web_app_setup_swipe_behavior', false, {allow_vertical_swipe: isVerticalSwipesEnabled}); | |
} | |
var headerColorKey = 'bg_color', headerColor = null; | |
function getHeaderColor() { | |
if (headerColorKey == 'secondary_bg_color') { | |
return themeParams.secondary_bg_color; | |
} else if (headerColorKey == 'bg_color') { | |
return themeParams.bg_color; | |
} | |
return headerColor; | |
} | |
function setHeaderColor(color) { | |
if (!versionAtLeast('6.1')) { | |
console.warn('[Telegram.WebApp] Header color is not supported in version ' + webAppVersion); | |
return; | |
} | |
if (!versionAtLeast('6.9')) { | |
if (themeParams.bg_color && | |
themeParams.bg_color == color) { | |
color = 'bg_color'; | |
} else if (themeParams.secondary_bg_color && | |
themeParams.secondary_bg_color == color) { | |
color = 'secondary_bg_color'; | |
} | |
} | |
var head_color = null, color_key = null; | |
if (color == 'bg_color' || color == 'secondary_bg_color') { | |
color_key = color; | |
} else if (versionAtLeast('6.9')) { | |
head_color = parseColorToHex(color); | |
if (!head_color) { | |
console.error('[Telegram.WebApp] Header color format is invalid', color); | |
throw Error('WebAppHeaderColorInvalid'); | |
} | |
} | |
if (!versionAtLeast('6.9') && | |
color_key != 'bg_color' && | |
color_key != 'secondary_bg_color') { | |
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); | |
throw Error('WebAppHeaderColorKeyInvalid'); | |
} | |
headerColorKey = color_key; | |
headerColor = head_color; | |
updateHeaderColor(); | |
} | |
var appHeaderColorKey = null, appHeaderColor = null; | |
function updateHeaderColor() { | |
if (appHeaderColorKey != headerColorKey || | |
appHeaderColor != headerColor) { | |
appHeaderColorKey = headerColorKey; | |
appHeaderColor = headerColor; | |
if (appHeaderColor) { | |
WebView.postEvent('web_app_set_header_color', false, {color: headerColor}); | |
} else { | |
WebView.postEvent('web_app_set_header_color', false, {color_key: headerColorKey}); | |
} | |
} | |
} | |
var backgroundColor = 'bg_color'; | |
function getBackgroundColor() { | |
if (backgroundColor == 'secondary_bg_color') { | |
return themeParams.secondary_bg_color; | |
} else if (backgroundColor == 'bg_color') { | |
return themeParams.bg_color; | |
} | |
return backgroundColor; | |
} | |
function setBackgroundColor(color) { | |
if (!versionAtLeast('6.1')) { | |
console.warn('[Telegram.WebApp] Background color is not supported in version ' + webAppVersion); | |
return; | |
} | |
var bg_color; | |
if (color == 'bg_color' || color == 'secondary_bg_color') { | |
bg_color = color; | |
} else { | |
bg_color = parseColorToHex(color); | |
if (!bg_color) { | |
console.error('[Telegram.WebApp] Background color format is invalid', color); | |
throw Error('WebAppBackgroundColorInvalid'); | |
} | |
} | |
backgroundColor = bg_color; | |
updateBackgroundColor(); | |
} | |
var appBackgroundColor = null; | |
function updateBackgroundColor() { | |
var color = getBackgroundColor(); | |
if (appBackgroundColor != color) { | |
appBackgroundColor = color; | |
WebView.postEvent('web_app_set_background_color', false, {color: color}); | |
} | |
} | |
function parseColorToHex(color) { | |
color += ''; | |
var match; | |
if (match = /^\s*#([0-9a-f]{6})\s*$/i.exec(color)) { | |
return '#' + match[1].toLowerCase(); | |
} | |
else if (match = /^\s*#([0-9a-f])([0-9a-f])([0-9a-f])\s*$/i.exec(color)) { | |
return ('#' + match[1] + match[1] + match[2] + match[2] + match[3] + match[3]).toLowerCase(); | |
} | |
else if (match = /^\s*rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)\s*$/.exec(color)) { | |
var r = parseInt(match[1]), g = parseInt(match[2]), b = parseInt(match[3]); | |
r = (r < 16 ? '0' : '') + r.toString(16); | |
g = (g < 16 ? '0' : '') + g.toString(16); | |
b = (b < 16 ? '0' : '') + b.toString(16); | |
return '#' + r + g + b; | |
} | |
return false; | |
} | |
function isColorDark(rgb) { | |
rgb = rgb.replace(/[\s#]/g, ''); | |
if (rgb.length == 3) { | |
rgb = rgb[0] + rgb[0] + rgb[1] + rgb[1] + rgb[2] + rgb[2]; | |
} | |
var r = parseInt(rgb.substr(0, 2), 16); | |
var g = parseInt(rgb.substr(2, 2), 16); | |
var b = parseInt(rgb.substr(4, 2), 16); | |
var hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b)); | |
return hsp < 120; | |
} | |
function versionCompare(v1, v2) { | |
if (typeof v1 !== 'string') v1 = ''; | |
if (typeof v2 !== 'string') v2 = ''; | |
v1 = v1.replace(/^\s+|\s+$/g, '').split('.'); | |
v2 = v2.replace(/^\s+|\s+$/g, '').split('.'); | |
var a = Math.max(v1.length, v2.length), i, p1, p2; | |
for (i = 0; i < a; i++) { | |
p1 = parseInt(v1[i]) || 0; | |
p2 = parseInt(v2[i]) || 0; | |
if (p1 == p2) continue; | |
if (p1 > p2) return 1; | |
return -1; | |
} | |
return 0; | |
} | |
function versionAtLeast(ver) { | |
return versionCompare(webAppVersion, ver) >= 0; | |
} | |
function byteLength(str) { | |
if (window.Blob) { | |
try { return new Blob([str]).size; } catch (e) {} | |
} | |
var s = str.length; | |
for (var i=str.length-1; i>=0; i--) { | |
var code = str.charCodeAt(i); | |
if (code > 0x7f && code <= 0x7ff) s++; | |
else if (code > 0x7ff && code <= 0xffff) s+=2; | |
if (code >= 0xdc00 && code <= 0xdfff) i--; | |
} | |
return s; | |
} | |
var BackButton = (function() { | |
var isVisible = false; | |
var backButton = {}; | |
Object.defineProperty(backButton, 'isVisible', { | |
set: function(val){ setParams({is_visible: val}); }, | |
get: function(){ return isVisible; }, | |
enumerable: true | |
}); | |
var curButtonState = null; | |
WebView.onEvent('back_button_pressed', onBackButtonPressed); | |
function onBackButtonPressed() { | |
receiveWebViewEvent('backButtonClicked'); | |
} | |
function buttonParams() { | |
return {is_visible: isVisible}; | |
} | |
function buttonState(btn_params) { | |
if (typeof btn_params === 'undefined') { | |
btn_params = buttonParams(); | |
} | |
return JSON.stringify(btn_params); | |
} | |
function buttonCheckVersion() { | |
if (!versionAtLeast('6.1')) { | |
console.warn('[Telegram.WebApp] BackButton is not supported in version ' + webAppVersion); | |
return false; | |
} | |
return true; | |
} | |
function updateButton() { | |
var btn_params = buttonParams(); | |
var btn_state = buttonState(btn_params); | |
if (curButtonState === btn_state) { | |
return; | |
} | |
curButtonState = btn_state; | |
WebView.postEvent('web_app_setup_back_button', false, btn_params); | |
} | |
function setParams(params) { | |
if (!buttonCheckVersion()) { | |
return backButton; | |
} | |
if (typeof params.is_visible !== 'undefined') { | |
isVisible = !!params.is_visible; | |
} | |
updateButton(); | |
return backButton; | |
} | |
backButton.onClick = function(callback) { | |
if (buttonCheckVersion()) { | |
onWebViewEvent('backButtonClicked', callback); | |
} | |
return backButton; | |
}; | |
backButton.offClick = function(callback) { | |
if (buttonCheckVersion()) { | |
offWebViewEvent('backButtonClicked', callback); | |
} | |
return backButton; | |
}; | |
backButton.show = function() { | |
return setParams({is_visible: true}); | |
}; | |
backButton.hide = function() { | |
return setParams({is_visible: false}); | |
}; | |
return backButton; | |
})(); | |
var mainButtonHeight = 0; | |
var MainButton = (function() { | |
var isVisible = false; | |
var isActive = true; | |
var isProgressVisible = false; | |
var buttonText = 'CONTINUE'; | |
var buttonColor = false; | |
var buttonTextColor = false; | |
var mainButton = {}; | |
Object.defineProperty(mainButton, 'text', { | |
set: function(val){ mainButton.setParams({text: val}); }, | |
get: function(){ return buttonText; }, | |
enumerable: true | |
}); | |
Object.defineProperty(mainButton, 'color', { | |
set: function(val){ mainButton.setParams({color: val}); }, | |
get: function(){ return buttonColor || themeParams.button_color || '#2481cc'; }, | |
enumerable: true | |
}); | |
Object.defineProperty(mainButton, 'textColor', { | |
set: function(val){ mainButton.setParams({text_color: val}); }, | |
get: function(){ return buttonTextColor || themeParams.button_text_color || '#ffffff'; }, | |
enumerable: true | |
}); | |
Object.defineProperty(mainButton, 'isVisible', { | |
set: function(val){ mainButton.setParams({is_visible: val}); }, | |
get: function(){ return isVisible; }, | |
enumerable: true | |
}); | |
Object.defineProperty(mainButton, 'isProgressVisible', { | |
get: function(){ return isProgressVisible; }, | |
enumerable: true | |
}); | |
Object.defineProperty(mainButton, 'isActive', { | |
set: function(val){ mainButton.setParams({is_active: val}); }, | |
get: function(){ return isActive; }, | |
enumerable: true | |
}); | |
var curButtonState = null; | |
WebView.onEvent('main_button_pressed', onMainButtonPressed); | |
var debugBtn = null, debugBtnStyle = {}; | |
if (initParams.tgWebAppDebug) { | |
debugBtn = document.createElement('tg-main-button'); | |
debugBtnStyle = { | |
font: '600 14px/18px sans-serif', | |
display: 'none', | |
width: '100%', | |
height: '48px', | |
borderRadius: '0', | |
background: 'no-repeat right center', | |
position: 'fixed', | |
left: '0', | |
right: '0', | |
bottom: '0', | |
margin: '0', | |
padding: '15px 20px', | |
textAlign: 'center', | |
boxSizing: 'border-box', | |
zIndex: '10000' | |
}; | |
for (var k in debugBtnStyle) { | |
debugBtn.style[k] = debugBtnStyle[k]; | |
} | |
document.addEventListener('DOMContentLoaded', function onDomLoaded(event) { | |
document.removeEventListener('DOMContentLoaded', onDomLoaded); | |
document.body.appendChild(debugBtn); | |
debugBtn.addEventListener('click', onMainButtonPressed, false); | |
}); | |
} | |
function onMainButtonPressed() { | |
if (isActive) { | |
receiveWebViewEvent('mainButtonClicked'); | |
} | |
} | |
function buttonParams() { | |
var color = mainButton.color; | |
var text_color = mainButton.textColor; | |
return isVisible ? { | |
is_visible: true, | |
is_active: isActive, | |
is_progress_visible: isProgressVisible, | |
text: buttonText, | |
color: color, | |
text_color: text_color | |
} : {is_visible: false}; | |
} | |
function buttonState(btn_params) { | |
if (typeof btn_params === 'undefined') { | |
btn_params = buttonParams(); | |
} | |
return JSON.stringify(btn_params); | |
} | |
function updateButton() { | |
var btn_params = buttonParams(); | |
var btn_state = buttonState(btn_params); | |
if (curButtonState === btn_state) { | |
return; | |
} | |
curButtonState = btn_state; | |
WebView.postEvent('web_app_setup_main_button', false, btn_params); | |
if (initParams.tgWebAppDebug) { | |
updateDebugButton(btn_params); | |
} | |
} | |
function updateDebugButton(btn_params) { | |
if (btn_params.is_visible) { | |
debugBtn.style.display = 'block'; | |
mainButtonHeight = 48; | |
debugBtn.style.opacity = btn_params.is_active ? '1' : '0.8'; | |
debugBtn.style.cursor = btn_params.is_active ? 'pointer' : 'auto'; | |
debugBtn.disabled = !btn_params.is_active; | |
debugBtn.innerText = btn_params.text; | |
debugBtn.style.backgroundImage = btn_params.is_progress_visible ? "url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20viewport%3D%220%200%2048%2048%22%20width%3D%2248px%22%20height%3D%2248px%22%3E%3Ccircle%20cx%3D%2250%25%22%20cy%3D%2250%25%22%20stroke%3D%22%23fff%22%20stroke-width%3D%222.25%22%20stroke-linecap%3D%22round%22%20fill%3D%22none%22%20stroke-dashoffset%3D%22106%22%20r%3D%229%22%20stroke-dasharray%3D%2256.52%22%20rotate%3D%22-90%22%3E%3Canimate%20attributeName%3D%22stroke-dashoffset%22%20attributeType%3D%22XML%22%20dur%3D%22360s%22%20from%3D%220%22%20to%3D%2212500%22%20repeatCount%3D%22indefinite%22%3E%3C%2Fanimate%3E%3CanimateTransform%20attributeName%3D%22transform%22%20attributeType%3D%22XML%22%20type%3D%22rotate%22%20dur%3D%221s%22%20from%3D%22-90%2024%2024%22%20to%3D%22630%2024%2024%22%20repeatCount%3D%22indefinite%22%3E%3C%2FanimateTransform%3E%3C%2Fcircle%3E%3C%2Fsvg%3E')" : 'none'; | |
debugBtn.style.backgroundColor = btn_params.color; | |
debugBtn.style.color = btn_params.text_color; | |
} else { | |
debugBtn.style.display = 'none'; | |
mainButtonHeight = 0; | |
} | |
if (document.documentElement) { | |
document.documentElement.style.boxSizing = 'border-box'; | |
document.documentElement.style.paddingBottom = mainButtonHeight + 'px'; | |
} | |
setViewportHeight(); | |
} | |
function setParams(params) { | |
if (typeof params.text !== 'undefined') { | |
var text = strTrim(params.text); | |
if (!text.length) { | |
console.error('[Telegram.WebApp] Main button text is required', params.text); | |
throw Error('WebAppMainButtonParamInvalid'); | |
} | |
if (text.length > 64) { | |
console.error('[Telegram.WebApp] Main button text is too long', text); | |
throw Error('WebAppMainButtonParamInvalid'); | |
} | |
buttonText = text; | |
} | |
if (typeof params.color !== 'undefined') { | |
if (params.color === false || | |
params.color === null) { | |
buttonColor = false; | |
} else { | |
var color = parseColorToHex(params.color); | |
if (!color) { | |
console.error('[Telegram.WebApp] Main button color format is invalid', params.color); | |
throw Error('WebAppMainButtonParamInvalid'); | |
} | |
buttonColor = color; | |
} | |
} | |
if (typeof params.text_color !== 'undefined') { | |
if (params.text_color === false || | |
params.text_color === null) { | |
buttonTextColor = false; | |
} else { | |
var text_color = parseColorToHex(params.text_color); | |
if (!text_color) { | |
console.error('[Telegram.WebApp] Main button text color format is invalid', params.text_color); | |
throw Error('WebAppMainButtonParamInvalid'); | |
} | |
buttonTextColor = text_color; | |
} | |
} | |
if (typeof params.is_visible !== 'undefined') { | |
if (params.is_visible && | |
!mainButton.text.length) { | |
console.error('[Telegram.WebApp] Main button text is required'); | |
throw Error('WebAppMainButtonParamInvalid'); | |
} | |
isVisible = !!params.is_visible; | |
} | |
if (typeof params.is_active !== 'undefined') { | |
isActive = !!params.is_active; | |
} | |
updateButton(); | |
return mainButton; | |
} | |
mainButton.setText = function(text) { | |
return mainButton.setParams({text: text}); | |
}; | |
mainButton.onClick = function(callback) { | |
onWebViewEvent('mainButtonClicked', callback); | |
return mainButton; | |
}; | |
mainButton.offClick = function(callback) { | |
offWebViewEvent('mainButtonClicked', callback); | |
return mainButton; | |
}; | |
mainButton.show = function() { | |
return mainButton.setParams({is_visible: true}); | |
}; | |
mainButton.hide = function() { | |
return mainButton.setParams({is_visible: false}); | |
}; | |
mainButton.enable = function() { | |
return mainButton.setParams({is_active: true}); | |
}; | |
mainButton.disable = function() { | |
return mainButton.setParams({is_active: false}); | |
}; | |
mainButton.showProgress = function(leaveActive) { | |
isActive = !!leaveActive; | |
isProgressVisible = true; | |
updateButton(); | |
return mainButton; | |
}; | |
mainButton.hideProgress = function() { | |
if (!mainButton.isActive) { | |
isActive = true; | |
} | |
isProgressVisible = false; | |
updateButton(); | |
return mainButton; | |
} | |
mainButton.setParams = setParams; | |
return mainButton; | |
})(); | |
var SettingsButton = (function() { | |
var isVisible = false; | |
var settingsButton = {}; | |
Object.defineProperty(settingsButton, 'isVisible', { | |
set: function(val){ setParams({is_visible: val}); }, | |
get: function(){ return isVisible; }, | |
enumerable: true | |
}); | |
var curButtonState = null; | |
WebView.onEvent('settings_button_pressed', onSettingsButtonPressed); | |
function onSettingsButtonPressed() { | |
receiveWebViewEvent('settingsButtonClicked'); | |
} | |
function buttonParams() { | |
return {is_visible: isVisible}; | |
} | |
function buttonState(btn_params) { | |
if (typeof btn_params === 'undefined') { | |
btn_params = buttonParams(); | |
} | |
return JSON.stringify(btn_params); | |
} | |
function buttonCheckVersion() { | |
if (!versionAtLeast('6.10')) { | |
console.warn('[Telegram.WebApp] SettingsButton is not supported in version ' + webAppVersion); | |
return false; | |
} | |
return true; | |
} | |
function updateButton() { | |
var btn_params = buttonParams(); | |
var btn_state = buttonState(btn_params); | |
if (curButtonState === btn_state) { | |
return; | |
} | |
curButtonState = btn_state; | |
WebView.postEvent('web_app_setup_settings_button', false, btn_params); | |
} | |
function setParams(params) { | |
if (!buttonCheckVersion()) { | |
return settingsButton; | |
} | |
if (typeof params.is_visible !== 'undefined') { | |
isVisible = !!params.is_visible; | |
} | |
updateButton(); | |
return settingsButton; | |
} | |
settingsButton.onClick = function(callback) { | |
if (buttonCheckVersion()) { | |
onWebViewEvent('settingsButtonClicked', callback); | |
} | |
return settingsButton; | |
}; | |
settingsButton.offClick = function(callback) { | |
if (buttonCheckVersion()) { | |
offWebViewEvent('settingsButtonClicked', callback); | |
} | |
return settingsButton; | |
}; | |
settingsButton.show = function() { | |
return setParams({is_visible: true}); | |
}; | |
settingsButton.hide = function() { | |
return setParams({is_visible: false}); | |
}; | |
return settingsButton; | |
})(); | |
var HapticFeedback = (function() { | |
var hapticFeedback = {}; | |
function triggerFeedback(params) { | |
if (!versionAtLeast('6.1')) { | |
console.warn('[Telegram.WebApp] HapticFeedback is not supported in version ' + webAppVersion); | |
return hapticFeedback; | |
} | |
if (params.type == 'impact') { | |
if (params.impact_style != 'light' && | |
params.impact_style != 'medium' && | |
params.impact_style != 'heavy' && | |
params.impact_style != 'rigid' && | |
params.impact_style != 'soft') { | |
console.error('[Telegram.WebApp] Haptic impact style is invalid', params.impact_style); | |
throw Error('WebAppHapticImpactStyleInvalid'); | |
} | |
} else if (params.type == 'notification') { | |
if (params.notification_type != 'error' && | |
params.notification_type != 'success' && | |
params.notification_type != 'warning') { | |
console.error('[Telegram.WebApp] Haptic notification type is invalid', params.notification_type); | |
throw Error('WebAppHapticNotificationTypeInvalid'); | |
} | |
} else if (params.type == 'selection_change') { | |
// no params needed | |
} else { | |
console.error('[Telegram.WebApp] Haptic feedback type is invalid', params.type); | |
throw Error('WebAppHapticFeedbackTypeInvalid'); | |
} | |
WebView.postEvent('web_app_trigger_haptic_feedback', false, params); | |
return hapticFeedback; | |
} | |
hapticFeedback.impactOccurred = function(style) { | |
return triggerFeedback({type: 'impact', impact_style: style}); | |
}; | |
hapticFeedback.notificationOccurred = function(type) { | |
return triggerFeedback({type: 'notification', notification_type: type}); | |
}; | |
hapticFeedback.selectionChanged = function() { | |
return triggerFeedback({type: 'selection_change'}); | |
}; | |
return hapticFeedback; | |
})(); | |
var CloudStorage = (function() { | |
var cloudStorage = {}; | |
function invokeStorageMethod(method, params, callback) { | |
if (!versionAtLeast('6.9')) { | |
console.error('[Telegram.WebApp] CloudStorage is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
invokeCustomMethod(method, params, callback); | |
return cloudStorage; | |
} | |
cloudStorage.setItem = function(key, value, callback) { | |
return invokeStorageMethod('saveStorageValue', {key: key, value: value}, callback); | |
}; | |
cloudStorage.getItem = function(key, callback) { | |
return cloudStorage.getItems([key], callback ? function(err, res) { | |
if (err) callback(err); | |
else callback(null, res[key]); | |
} : null); | |
}; | |
cloudStorage.getItems = function(keys, callback) { | |
return invokeStorageMethod('getStorageValues', {keys: keys}, callback); | |
}; | |
cloudStorage.removeItem = function(key, callback) { | |
return cloudStorage.removeItems([key], callback); | |
}; | |
cloudStorage.removeItems = function(keys, callback) { | |
return invokeStorageMethod('deleteStorageValues', {keys: keys}, callback); | |
}; | |
cloudStorage.getKeys = function(callback) { | |
return invokeStorageMethod('getStorageKeys', {}, callback); | |
}; | |
return cloudStorage; | |
})(); | |
var BiometricManager = (function() { | |
var isInited = false; | |
var isBiometricAvailable = false; | |
var biometricType = 'unknown'; | |
var isAccessRequested = false; | |
var isAccessGranted = false; | |
var isBiometricTokenSaved = false; | |
var deviceId = ''; | |
var biometricManager = {}; | |
Object.defineProperty(biometricManager, 'isInited', { | |
get: function(){ return isInited; }, | |
enumerable: true | |
}); | |
Object.defineProperty(biometricManager, 'isBiometricAvailable', { | |
get: function(){ return isInited && isBiometricAvailable; }, | |
enumerable: true | |
}); | |
Object.defineProperty(biometricManager, 'biometricType', { | |
get: function(){ return biometricType || 'unknown'; }, | |
enumerable: true | |
}); | |
Object.defineProperty(biometricManager, 'isAccessRequested', { | |
get: function(){ return isAccessRequested; }, | |
enumerable: true | |
}); | |
Object.defineProperty(biometricManager, 'isAccessGranted', { | |
get: function(){ return isAccessRequested && isAccessGranted; }, | |
enumerable: true | |
}); | |
Object.defineProperty(biometricManager, 'isBiometricTokenSaved', { | |
get: function(){ return isBiometricTokenSaved; }, | |
enumerable: true | |
}); | |
Object.defineProperty(biometricManager, 'deviceId', { | |
get: function(){ return deviceId || ''; }, | |
enumerable: true | |
}); | |
var initRequestState = {callbacks: []}; | |
var accessRequestState = false; | |
var authRequestState = false; | |
var tokenRequestState = false; | |
WebView.onEvent('biometry_info_received', onBiometryInfoReceived); | |
WebView.onEvent('biometry_auth_requested', onBiometryAuthRequested); | |
WebView.onEvent('biometry_token_updated', onBiometryTokenUpdated); | |
function onBiometryInfoReceived(eventType, eventData) { | |
isInited = true; | |
if (eventData.available) { | |
isBiometricAvailable = true; | |
biometricType = eventData.type || 'unknown'; | |
if (eventData.access_requested) { | |
isAccessRequested = true; | |
isAccessGranted = !!eventData.access_granted; | |
isBiometricTokenSaved = !!eventData.token_saved; | |
} else { | |
isAccessRequested = false; | |
isAccessGranted = false; | |
isBiometricTokenSaved = false; | |
} | |
} else { | |
isBiometricAvailable = false; | |
biometricType = 'unknown'; | |
isAccessRequested = false; | |
isAccessGranted = false; | |
isBiometricTokenSaved = false; | |
} | |
deviceId = eventData.device_id || ''; | |
if (initRequestState.callbacks.length > 0) { | |
for (var i = 0; i < initRequestState.callbacks.length; i++) { | |
var callback = initRequestState.callbacks[i]; | |
callback(); | |
} | |
} | |
if (accessRequestState) { | |
var state = accessRequestState; | |
accessRequestState = false; | |
if (state.callback) { | |
state.callback(isAccessGranted); | |
} | |
} | |
receiveWebViewEvent('biometricManagerUpdated'); | |
} | |
function onBiometryAuthRequested(eventType, eventData) { | |
var isAuthenticated = (eventData.status == 'authorized'), | |
biometricToken = eventData.token || ''; | |
if (authRequestState) { | |
var state = authRequestState; | |
authRequestState = false; | |
if (state.callback) { | |
state.callback(isAuthenticated, isAuthenticated ? biometricToken : null); | |
} | |
} | |
receiveWebViewEvent('biometricAuthRequested', isAuthenticated ? { | |
isAuthenticated: true, | |
biometricToken: biometricToken | |
} : { | |
isAuthenticated: false | |
}); | |
} | |
function onBiometryTokenUpdated(eventType, eventData) { | |
var applied = false; | |
if (isBiometricAvailable && | |
isAccessRequested) { | |
if (eventData.status == 'updated') { | |
isBiometricTokenSaved = true; | |
applied = true; | |
} | |
else if (eventData.status == 'removed') { | |
isBiometricTokenSaved = false; | |
applied = true; | |
} | |
} | |
if (tokenRequestState) { | |
var state = tokenRequestState; | |
tokenRequestState = false; | |
if (state.callback) { | |
state.callback(applied); | |
} | |
} | |
receiveWebViewEvent('biometricTokenUpdated', { | |
isUpdated: applied | |
}); | |
} | |
function checkVersion() { | |
if (!versionAtLeast('7.2')) { | |
console.warn('[Telegram.WebApp] BiometricManager is not supported in version ' + webAppVersion); | |
return false; | |
} | |
return true; | |
} | |
function checkInit() { | |
if (!isInited) { | |
console.error('[Telegram.WebApp] BiometricManager should be inited before using.'); | |
throw Error('WebAppBiometricManagerNotInited'); | |
} | |
return true; | |
} | |
biometricManager.init = function(callback) { | |
if (!checkVersion()) { | |
return biometricManager; | |
} | |
if (isInited) { | |
return biometricManager; | |
} | |
if (callback) { | |
initRequestState.callbacks.push(callback); | |
} | |
WebView.postEvent('web_app_biometry_get_info', false); | |
return biometricManager; | |
}; | |
biometricManager.requestAccess = function(params, callback) { | |
if (!checkVersion()) { | |
return biometricManager; | |
} | |
checkInit(); | |
if (!isBiometricAvailable) { | |
console.error('[Telegram.WebApp] Biometrics is not available on this device.'); | |
throw Error('WebAppBiometricManagerBiometricsNotAvailable'); | |
} | |
if (accessRequestState) { | |
console.error('[Telegram.WebApp] Access is already requested'); | |
throw Error('WebAppBiometricManagerAccessRequested'); | |
} | |
var popup_params = {}; | |
if (typeof params.reason !== 'undefined') { | |
var reason = strTrim(params.reason); | |
if (reason.length > 128) { | |
console.error('[Telegram.WebApp] Biometric reason is too long', reason); | |
throw Error('WebAppBiometricRequestAccessParamInvalid'); | |
} | |
if (reason.length > 0) { | |
popup_params.reason = reason; | |
} | |
} | |
accessRequestState = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_biometry_request_access', false, popup_params); | |
return biometricManager; | |
}; | |
biometricManager.authenticate = function(params, callback) { | |
if (!checkVersion()) { | |
return biometricManager; | |
} | |
checkInit(); | |
if (!isBiometricAvailable) { | |
console.error('[Telegram.WebApp] Biometrics is not available on this device.'); | |
throw Error('WebAppBiometricManagerBiometricsNotAvailable'); | |
} | |
if (!isAccessGranted) { | |
console.error('[Telegram.WebApp] Biometric access was not granted by the user.'); | |
throw Error('WebAppBiometricManagerBiometricAccessNotGranted'); | |
} | |
if (authRequestState) { | |
console.error('[Telegram.WebApp] Authentication request is already in progress.'); | |
throw Error('WebAppBiometricManagerAuthenticationRequested'); | |
} | |
var popup_params = {}; | |
if (typeof params.reason !== 'undefined') { | |
var reason = strTrim(params.reason); | |
if (reason.length > 128) { | |
console.error('[Telegram.WebApp] Biometric reason is too long', reason); | |
throw Error('WebAppBiometricRequestAccessParamInvalid'); | |
} | |
if (reason.length > 0) { | |
popup_params.reason = reason; | |
} | |
} | |
authRequestState = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_biometry_request_auth', false, popup_params); | |
return biometricManager; | |
}; | |
biometricManager.updateBiometricToken = function(token, callback) { | |
if (!checkVersion()) { | |
return biometricManager; | |
} | |
token = token || ''; | |
if (token.length > 1024) { | |
console.error('[Telegram.WebApp] Token is too long', token); | |
throw Error('WebAppBiometricManagerTokenInvalid'); | |
} | |
checkInit(); | |
if (!isBiometricAvailable) { | |
console.error('[Telegram.WebApp] Biometrics is not available on this device.'); | |
throw Error('WebAppBiometricManagerBiometricsNotAvailable'); | |
} | |
if (!isAccessGranted) { | |
console.error('[Telegram.WebApp] Biometric access was not granted by the user.'); | |
throw Error('WebAppBiometricManagerBiometricAccessNotGranted'); | |
} | |
if (tokenRequestState) { | |
console.error('[Telegram.WebApp] Token request is already in progress.'); | |
throw Error('WebAppBiometricManagerTokenUpdateRequested'); | |
} | |
tokenRequestState = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_biometry_update_token', false, {token: token}); | |
return biometricManager; | |
}; | |
biometricManager.openSettings = function() { | |
if (!checkVersion()) { | |
return biometricManager; | |
} | |
checkInit(); | |
if (!isBiometricAvailable) { | |
console.error('[Telegram.WebApp] Biometrics is not available on this device.'); | |
throw Error('WebAppBiometricManagerBiometricsNotAvailable'); | |
} | |
if (!isAccessRequested) { | |
console.error('[Telegram.WebApp] Biometric access was not requested yet.'); | |
throw Error('WebAppBiometricManagerBiometricsAccessNotRequested'); | |
} | |
if (isAccessGranted) { | |
console.warn('[Telegram.WebApp] Biometric access was granted by the user, no need to go to settings.'); | |
return biometricManager; | |
} | |
WebView.postEvent('web_app_biometry_open_settings', false); | |
return biometricManager; | |
}; | |
return biometricManager; | |
})(); | |
var webAppInvoices = {}; | |
function onInvoiceClosed(eventType, eventData) { | |
if (eventData.slug && webAppInvoices[eventData.slug]) { | |
var invoiceData = webAppInvoices[eventData.slug]; | |
delete webAppInvoices[eventData.slug]; | |
if (invoiceData.callback) { | |
invoiceData.callback(eventData.status); | |
} | |
receiveWebViewEvent('invoiceClosed', { | |
url: invoiceData.url, | |
status: eventData.status | |
}); | |
} | |
} | |
var webAppPopupOpened = false; | |
function onPopupClosed(eventType, eventData) { | |
if (webAppPopupOpened) { | |
var popupData = webAppPopupOpened; | |
webAppPopupOpened = false; | |
var button_id = null; | |
if (typeof eventData.button_id !== 'undefined') { | |
button_id = eventData.button_id; | |
} | |
if (popupData.callback) { | |
popupData.callback(button_id); | |
} | |
receiveWebViewEvent('popupClosed', { | |
button_id: button_id | |
}); | |
} | |
} | |
var webAppScanQrPopupOpened = false; | |
function onQrTextReceived(eventType, eventData) { | |
if (webAppScanQrPopupOpened) { | |
var popupData = webAppScanQrPopupOpened; | |
var data = null; | |
if (typeof eventData.data !== 'undefined') { | |
data = eventData.data; | |
} | |
if (popupData.callback) { | |
if (popupData.callback(data)) { | |
webAppScanQrPopupOpened = false; | |
WebView.postEvent('web_app_close_scan_qr_popup', false); | |
} | |
} | |
receiveWebViewEvent('qrTextReceived', { | |
data: data | |
}); | |
} | |
} | |
function onScanQrPopupClosed(eventType, eventData) { | |
webAppScanQrPopupOpened = false; | |
receiveWebViewEvent('scanQrPopupClosed'); | |
} | |
function onClipboardTextReceived(eventType, eventData) { | |
if (eventData.req_id && webAppCallbacks[eventData.req_id]) { | |
var requestData = webAppCallbacks[eventData.req_id]; | |
delete webAppCallbacks[eventData.req_id]; | |
var data = null; | |
if (typeof eventData.data !== 'undefined') { | |
data = eventData.data; | |
} | |
if (requestData.callback) { | |
requestData.callback(data); | |
} | |
receiveWebViewEvent('clipboardTextReceived', { | |
data: data | |
}); | |
} | |
} | |
var WebAppWriteAccessRequested = false; | |
function onWriteAccessRequested(eventType, eventData) { | |
if (WebAppWriteAccessRequested) { | |
var requestData = WebAppWriteAccessRequested; | |
WebAppWriteAccessRequested = false; | |
if (requestData.callback) { | |
requestData.callback(eventData.status == 'allowed'); | |
} | |
receiveWebViewEvent('writeAccessRequested', { | |
status: eventData.status | |
}); | |
} | |
} | |
function getRequestedContact(callback, timeout) { | |
var reqTo, fallbackTo, reqDelay = 0; | |
var reqInvoke = function() { | |
invokeCustomMethod('getRequestedContact', {}, function(err, res) { | |
if (res && res.length) { | |
clearTimeout(fallbackTo); | |
callback(res); | |
} else { | |
reqDelay += 50; | |
reqTo = setTimeout(reqInvoke, reqDelay); | |
} | |
}); | |
}; | |
var fallbackInvoke = function() { | |
clearTimeout(reqTo); | |
callback(''); | |
}; | |
fallbackTo = setTimeout(fallbackInvoke, timeout); | |
reqInvoke(); | |
} | |
var WebAppContactRequested = false; | |
function onPhoneRequested(eventType, eventData) { | |
if (WebAppContactRequested) { | |
var requestData = WebAppContactRequested; | |
WebAppContactRequested = false; | |
var requestSent = eventData.status == 'sent'; | |
var webViewEvent = { | |
status: eventData.status | |
}; | |
if (requestSent) { | |
getRequestedContact(function(res) { | |
if (res && res.length) { | |
webViewEvent.response = res; | |
webViewEvent.responseUnsafe = Utils.urlParseQueryString(res); | |
for (var key in webViewEvent.responseUnsafe) { | |
var val = webViewEvent.responseUnsafe[key]; | |
try { | |
if (val.substr(0, 1) == '{' && val.substr(-1) == '}' || | |
val.substr(0, 1) == '[' && val.substr(-1) == ']') { | |
webViewEvent.responseUnsafe[key] = JSON.parse(val); | |
} | |
} catch (e) {} | |
} | |
} | |
if (requestData.callback) { | |
requestData.callback(requestSent, webViewEvent); | |
} | |
receiveWebViewEvent('contactRequested', webViewEvent); | |
}, 3000); | |
} else { | |
if (requestData.callback) { | |
requestData.callback(requestSent, webViewEvent); | |
} | |
receiveWebViewEvent('contactRequested', webViewEvent); | |
} | |
} | |
} | |
function onCustomMethodInvoked(eventType, eventData) { | |
if (eventData.req_id && webAppCallbacks[eventData.req_id]) { | |
var requestData = webAppCallbacks[eventData.req_id]; | |
delete webAppCallbacks[eventData.req_id]; | |
var res = null, err = null; | |
if (typeof eventData.result !== 'undefined') { | |
res = eventData.result; | |
} | |
if (typeof eventData.error !== 'undefined') { | |
err = eventData.error; | |
} | |
if (requestData.callback) { | |
requestData.callback(err, res); | |
} | |
} | |
} | |
function invokeCustomMethod(method, params, callback) { | |
if (!versionAtLeast('6.9')) { | |
console.error('[Telegram.WebApp] Method invokeCustomMethod is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
var req_id = generateCallbackId(16); | |
var req_params = {req_id: req_id, method: method, params: params || {}}; | |
webAppCallbacks[req_id] = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_invoke_custom_method', false, req_params); | |
}; | |
if (!window.Telegram) { | |
window.Telegram = {}; | |
} | |
Object.defineProperty(WebApp, 'initData', { | |
get: function(){ return webAppInitData; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'initDataUnsafe', { | |
get: function(){ return webAppInitDataUnsafe; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'version', { | |
get: function(){ return webAppVersion; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'platform', { | |
get: function(){ return webAppPlatform; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'colorScheme', { | |
get: function(){ return colorScheme; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'themeParams', { | |
get: function(){ return themeParams; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'isExpanded', { | |
get: function(){ return isExpanded; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'viewportHeight', { | |
get: function(){ return (viewportHeight === false ? window.innerHeight : viewportHeight) - mainButtonHeight; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'viewportStableHeight', { | |
get: function(){ return (viewportStableHeight === false ? window.innerHeight : viewportStableHeight) - mainButtonHeight; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'isClosingConfirmationEnabled', { | |
set: function(val){ setClosingConfirmation(val); }, | |
get: function(){ return isClosingConfirmationEnabled; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'isVerticalSwipesEnabled', { | |
set: function(val){ toggleVerticalSwipes(val); }, | |
get: function(){ return isVerticalSwipesEnabled; }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'headerColor', { | |
set: function(val){ setHeaderColor(val); }, | |
get: function(){ return getHeaderColor(); }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'backgroundColor', { | |
set: function(val){ setBackgroundColor(val); }, | |
get: function(){ return getBackgroundColor(); }, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'BackButton', { | |
value: BackButton, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'MainButton', { | |
value: MainButton, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'SettingsButton', { | |
value: SettingsButton, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'HapticFeedback', { | |
value: HapticFeedback, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'CloudStorage', { | |
value: CloudStorage, | |
enumerable: true | |
}); | |
Object.defineProperty(WebApp, 'BiometricManager', { | |
value: BiometricManager, | |
enumerable: true | |
}); | |
WebApp.setHeaderColor = function(color_key) { | |
WebApp.headerColor = color_key; | |
}; | |
WebApp.setBackgroundColor = function(color) { | |
WebApp.backgroundColor = color; | |
}; | |
WebApp.enableClosingConfirmation = function() { | |
WebApp.isClosingConfirmationEnabled = true; | |
}; | |
WebApp.disableClosingConfirmation = function() { | |
WebApp.isClosingConfirmationEnabled = false; | |
}; | |
WebApp.enableVerticalSwipes = function() { | |
WebApp.isVerticalSwipesEnabled = true; | |
}; | |
WebApp.disableVerticalSwipes = function() { | |
WebApp.isVerticalSwipesEnabled = false; | |
}; | |
WebApp.isVersionAtLeast = function(ver) { | |
return versionAtLeast(ver); | |
}; | |
WebApp.onEvent = function(eventType, callback) { | |
onWebViewEvent(eventType, callback); | |
}; | |
WebApp.offEvent = function(eventType, callback) {offWebViewEvent(eventType, callback); | |
}; | |
WebApp.sendData = function (data) { | |
if (!data || !data.length) { | |
console.error('[Telegram.WebApp] Data is required', data); | |
throw Error('WebAppDataInvalid'); | |
} | |
if (byteLength(data) > 4096) { | |
console.error('[Telegram.WebApp] Data is too long', data); | |
throw Error('WebAppDataInvalid'); | |
} | |
WebView.postEvent('web_app_data_send', false, {data: data}); | |
}; | |
WebApp.switchInlineQuery = function (query, choose_chat_types) { | |
if (!versionAtLeast('6.6')) { | |
console.error('[Telegram.WebApp] Method switchInlineQuery is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
if (!initParams.tgWebAppBotInline) { | |
console.error('[Telegram.WebApp] Inline mode is disabled for this bot. Read more about inline mode: https://core.telegram.org/bots/inline'); | |
throw Error('WebAppInlineModeDisabled'); | |
} | |
query = query || ''; | |
if (query.length > 256) { | |
console.error('[Telegram.WebApp] Inline query is too long', query); | |
throw Error('WebAppInlineQueryInvalid'); | |
} | |
var chat_types = []; | |
if (choose_chat_types) { | |
if (!Array.isArray(choose_chat_types)) { | |
console.error('[Telegram.WebApp] Choose chat types should be an array', choose_chat_types); | |
throw Error('WebAppInlineChooseChatTypesInvalid'); | |
} | |
var good_types = {users: 1, bots: 1, groups: 1, channels: 1}; | |
for (var i = 0; i < choose_chat_types.length; i++) { | |
var chat_type = choose_chat_types[i]; | |
if (!good_types[chat_type]) { | |
console.error('[Telegram.WebApp] Choose chat type is invalid', chat_type); | |
throw Error('WebAppInlineChooseChatTypeInvalid'); | |
} | |
if (good_types[chat_type] != 2) { | |
good_types[chat_type] = 2; | |
chat_types.push(chat_type); | |
} | |
} | |
} | |
WebView.postEvent('web_app_switch_inline_query', false, {query: query, chat_types: chat_types}); | |
}; | |
WebApp.openLink = function (url, options) { | |
var a = document.createElement('A'); | |
a.href = url; | |
if (a.protocol != 'http:' && | |
a.protocol != 'https:') { | |
console.error('[Telegram.WebApp] Url protocol is not supported', url); | |
throw Error('WebAppTgUrlInvalid'); | |
} | |
var url = a.href; | |
options = options || {}; | |
if (versionAtLeast('6.1')) { | |
var req_params = {url: url}; | |
if (versionAtLeast('6.4') && options.try_instant_view) { | |
req_params.try_instant_view = true; | |
} | |
if (versionAtLeast('7.6') && options.try_browser) { | |
req_params.try_browser = options.try_browser; | |
} | |
WebView.postEvent('web_app_open_link', false, req_params); | |
} else { | |
window.open(url, '_blank'); | |
} | |
}; | |
WebApp.openTelegramLink = function (url) { | |
var a = document.createElement('A'); | |
a.href = url; | |
if (a.protocol != 'http:' && | |
a.protocol != 'https:') { | |
console.error('[Telegram.WebApp] Url protocol is not supported', url); | |
throw Error('WebAppTgUrlInvalid'); | |
} | |
if (a.hostname != 't.me') { | |
console.error('[Telegram.WebApp] Url host is not supported', url); | |
throw Error('WebAppTgUrlInvalid'); | |
} | |
var path_full = a.pathname + a.search; | |
if (isIframe || versionAtLeast('6.1')) { | |
WebView.postEvent('web_app_open_tg_link', false, {path_full: path_full}); | |
} else { | |
location.href = 'https://t.me' + path_full; | |
} | |
}; | |
WebApp.openInvoice = function (url, callback) { | |
var a = document.createElement('A'), match, slug; | |
a.href = url; | |
if (a.protocol != 'http:' && | |
a.protocol != 'https:' || | |
a.hostname != 't.me' || | |
!(match = a.pathname.match(/^\/(\$|invoice\/)([A-Za-z0-9\-_=]+)$/)) || | |
!(slug = match[2])) { | |
console.error('[Telegram.WebApp] Invoice url is invalid', url); | |
throw Error('WebAppInvoiceUrlInvalid'); | |
} | |
if (!versionAtLeast('6.1')) { | |
console.error('[Telegram.WebApp] Method openInvoice is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
if (webAppInvoices[slug]) { | |
console.error('[Telegram.WebApp] Invoice is already opened'); | |
throw Error('WebAppInvoiceOpened'); | |
} | |
webAppInvoices[slug] = { | |
url: url, | |
callback: callback | |
}; | |
WebView.postEvent('web_app_open_invoice', false, {slug: slug}); | |
}; | |
WebApp.showPopup = function (params, callback) { | |
if (!versionAtLeast('6.2')) { | |
console.error('[Telegram.WebApp] Method showPopup is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
if (webAppPopupOpened) { | |
console.error('[Telegram.WebApp] Popup is already opened'); | |
throw Error('WebAppPopupOpened'); | |
} | |
var title = ''; | |
var message = ''; | |
var buttons = []; | |
var popup_buttons = {}; | |
var popup_params = {}; | |
if (typeof params.title !== 'undefined') { | |
title = strTrim(params.title); | |
if (title.length > 64) { | |
console.error('[Telegram.WebApp] Popup title is too long', title); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
if (title.length > 0) { | |
popup_params.title = title; | |
} | |
} | |
if (typeof params.message !== 'undefined') { | |
message = strTrim(params.message); | |
} | |
if (!message.length) { | |
console.error('[Telegram.WebApp] Popup message is required', params.message); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
if (message.length > 256) { | |
console.error('[Telegram.WebApp] Popup message is too long', message); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
popup_params.message = message; | |
if (typeof params.buttons !== 'undefined') { | |
if (!Array.isArray(params.buttons)) { | |
console.error('[Telegram.WebApp] Popup buttons should be an array', params.buttons); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
for (var i = 0; i < params.buttons.length; i++) { | |
var button = params.buttons[i]; | |
var btn = {}; | |
var id = ''; | |
if (typeof button.id !== 'undefined') { | |
id = button.id.toString(); | |
if (id.length > 64) { | |
console.error('[Telegram.WebApp] Popup button id is too long', id); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
} | |
btn.id = id; | |
var button_type = button.type; | |
if (typeof button_type === 'undefined') { | |
button_type = 'default'; | |
} | |
btn.type = button_type; | |
if (button_type == 'ok' || | |
button_type == 'close' || | |
button_type == 'cancel') { | |
// no params needed | |
} else if (button_type == 'default' || | |
button_type == 'destructive') { | |
var text = ''; | |
if (typeof button.text !== 'undefined') { | |
text = strTrim(button.text); | |
} | |
if (!text.length) { | |
console.error('[Telegram.WebApp] Popup button text is required for type ' + button_type, button.text); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
if (text.length > 64) { | |
console.error('[Telegram.WebApp] Popup button text is too long', text); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
btn.text = text; | |
} else { | |
console.error('[Telegram.WebApp] Popup button type is invalid', button_type); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
buttons.push(btn); | |
} | |
} else { | |
buttons.push({id: '', type: 'close'}); | |
} | |
if (buttons.length < 1) { | |
console.error('[Telegram.WebApp] Popup should have at least one button'); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
if (buttons.length > 3) { | |
console.error('[Telegram.WebApp] Popup should not have more than 3 buttons'); | |
throw Error('WebAppPopupParamInvalid'); | |
} | |
popup_params.buttons = buttons; | |
webAppPopupOpened = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_open_popup', false, popup_params); | |
}; | |
WebApp.showAlert = function (message, callback) { | |
WebApp.showPopup({ | |
message: message | |
}, callback ? function(){ callback(); } : null); | |
}; | |
WebApp.showConfirm = function (message, callback) { | |
WebApp.showPopup({ | |
message: message, | |
buttons: [ | |
{type: 'ok', id: 'ok'}, | |
{type: 'cancel'} | |
] | |
}, callback ? function (button_id) { | |
callback(button_id == 'ok'); | |
} : null); | |
}; | |
WebApp.showScanQrPopup = function (params, callback) { | |
if (!versionAtLeast('6.4')) { | |
console.error('[Telegram.WebApp] Method showScanQrPopup is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
if (webAppScanQrPopupOpened) { | |
console.error('[Telegram.WebApp] Popup is already opened'); | |
throw Error('WebAppScanQrPopupOpened'); | |
} | |
var text = ''; | |
var popup_params = {}; | |
if (typeof params.text !== 'undefined') { | |
text = strTrim(params.text); | |
if (text.length > 64) { | |
console.error('[Telegram.WebApp] Scan QR popup text is too long', text); | |
throw Error('WebAppScanQrPopupParamInvalid'); | |
} | |
if (text.length > 0) { | |
popup_params.text = text; | |
} | |
} | |
webAppScanQrPopupOpened = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_open_scan_qr_popup', false, popup_params); | |
}; | |
WebApp.closeScanQrPopup = function () { | |
if (!versionAtLeast('6.4')) { | |
console.error('[Telegram.WebApp] Method closeScanQrPopup is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
webAppScanQrPopupOpened = false; | |
WebView.postEvent('web_app_close_scan_qr_popup', false); | |
}; | |
WebApp.readTextFromClipboard = function (callback) { | |
if (!versionAtLeast('6.4')) { | |
console.error('[Telegram.WebApp] Method readTextFromClipboard is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
var req_id = generateCallbackId(16); | |
var req_params = {req_id: req_id}; | |
webAppCallbacks[req_id] = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_read_text_from_clipboard', false, req_params); | |
}; | |
WebApp.requestWriteAccess = function (callback) { | |
if (!versionAtLeast('6.9')) { | |
console.error('[Telegram.WebApp] Method requestWriteAccess is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
if (WebAppWriteAccessRequested) { | |
console.error('[Telegram.WebApp] Write access is already requested'); | |
throw Error('WebAppWriteAccessRequested'); | |
} | |
WebAppWriteAccessRequested = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_request_write_access'); | |
}; | |
WebApp.requestContact = function (callback) { | |
if (!versionAtLeast('6.9')) { | |
console.error('[Telegram.WebApp] Method requestContact is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
if (WebAppContactRequested) { | |
console.error('[Telegram.WebApp] Contact is already requested'); | |
throw Error('WebAppContactRequested'); | |
} | |
WebAppContactRequested = { | |
callback: callback | |
}; | |
WebView.postEvent('web_app_request_phone'); | |
}; | |
WebApp.shareToStory = function (media_url, params) { | |
params = params || {}; | |
if (!versionAtLeast('7.8')) { | |
console.error('[Telegram.WebApp] Method shareToStory is not supported in version ' + webAppVersion); | |
throw Error('WebAppMethodUnsupported'); | |
} | |
var a = document.createElement('A'); | |
a.href = media_url; | |
if (a.protocol != 'http:' && | |
a.protocol != 'https:') { | |
console.error('[Telegram.WebApp] Media url protocol is not supported', url); | |
throw Error('WebAppMediaUrlInvalid'); | |
} | |
var share_params = {}; | |
share_params.media_url = a.href; | |
if (typeof params.text !== 'undefined') { | |
var text = strTrim(params.text); | |
if (text.length > 2048) { | |
console.error('[Telegram.WebApp] Text is too long', text); | |
throw Error('WebAppShareToStoryParamInvalid'); | |
} | |
if (text.length > 0) { | |
share_params.text = text; | |
} | |
} | |
if (typeof params.widget_link !== 'undefined') { | |
params.widget_link = params.widget_link || {}; | |
a.href = params.widget_link.url; | |
if (a.protocol != 'http:' && | |
a.protocol != 'https:') { | |
console.error('[Telegram.WebApp] Link protocol is not supported', url); | |
throw Error('WebAppShareToStoryParamInvalid'); | |
} | |
var widget_link = { | |
url: a.href | |
}; | |
if (typeof params.widget_link.name !== 'undefined') { | |
var link_name = strTrim(params.widget_link.name); | |
if (link_name.length > 48) { | |
console.error('[Telegram.WebApp] Link name is too long', link_name); | |
throw Error('WebAppShareToStoryParamInvalid'); | |
} | |
if (link_name.length > 0) { | |
widget_link.name = link_name; | |
} | |
} | |
share_params.widget_link = widget_link; | |
} | |
WebView.postEvent('web_app_share_to_story', false, share_params); | |
}; | |
WebApp.invokeCustomMethod = function (method, params, callback) { | |
invokeCustomMethod(method, params, callback); | |
}; | |
WebApp.ready = function () { | |
WebView.postEvent('web_app_ready'); | |
}; | |
WebApp.expand = function () { | |
WebView.postEvent('web_app_expand'); | |
}; | |
WebApp.close = function (options) { | |
options = options || {}; | |
var req_params = {}; | |
if (versionAtLeast('7.6') && options.return_back) { | |
req_params.return_back = true; | |
} | |
WebView.postEvent('web_app_close', false, req_params); | |
}; | |
window.Telegram.WebApp = WebApp; | |
updateHeaderColor(); | |
updateBackgroundColor(); | |
setViewportHeight(); | |
if (initParams.tgWebAppShowSettings) { | |
SettingsButton.show(); | |
} | |
window.addEventListener('resize', onWindowResize); | |
if (isIframe) { | |
document.addEventListener('click', linkHandler); | |
} | |
WebView.onEvent('theme_changed', onThemeChanged); | |
WebView.onEvent('viewport_changed', onViewportChanged); | |
WebView.onEvent('invoice_closed', onInvoiceClosed); | |
WebView.onEvent('popup_closed', onPopupClosed); | |
WebView.onEvent('qr_text_received', onQrTextReceived); | |
WebView.onEvent('scan_qr_popup_closed', onScanQrPopupClosed); | |
WebView.onEvent('clipboard_text_received', onClipboardTextReceived); | |
WebView.onEvent('write_access_requested', onWriteAccessRequested); | |
WebView.onEvent('phone_requested', onPhoneRequested); | |
WebView.onEvent('custom_method_invoked', onCustomMethodInvoked); | |
WebView.postEvent('web_app_request_theme'); | |
WebView.postEvent('web_app_request_viewport'); | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let telegram | |
function ContinueTelegram() { | |
const user_id = telegram.initDataUnsafe.user.id | |
const group_id = telegram.initDataUnsafe.start_param | |
if (group_id === undefined) { | |
telegram.showAlert('Use the /join command to join Group Music.', callback = () => { | |
telegram.close() | |
}) | |
return | |
} | |
telegram.enableClosingConfirmation() | |
InitWebsite(user_id, group_id) | |
} | |
document.addEventListener('DOMContentLoaded', () => { | |
telegram = window.Telegram.WebApp | |
document.getElementById('join-btn').addEventListener('click', () => { | |
document.getElementById('join-div').style.display = 'none'; | |
document.getElementById('loader').style.display = 'flex'; | |
telegram.ready() | |
telegram.expand() | |
telegram.setHeaderColor('#000813') | |
telegram.setBackgroundColor('#000813') | |
if (!telegram.isVersionAtLeast('7.6')) { | |
telegram.showPopup( | |
{ | |
'title': 'Update Required', | |
'message': `Please update your Telegram app to continue using TechZMusic. Your current version is ${telegram.version}, but TechZMusic requires version 7.6 or higher to function properly.`, | |
'buttons': [ | |
{ | |
'id': 'Close', | |
'text': 'Close' | |
}, | |
] | |
} | |
) | |
telegram.onEvent('popupClosed', function (data) { | |
telegram.close() | |
}) | |
} | |
else { | |
ContinueTelegram() | |
} | |
}) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment