add web
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,216 @@
|
||||
async function initVoteContainer( containerElement ) {
|
||||
const assetId = containerElement.getAttribute('data-assetid')
|
||||
const XCSRFToken = document.getElementById('X-CSRF-TOKEN').getAttribute('data-xcsrf')
|
||||
if ( XCSRFToken == null ) {
|
||||
console.log('XCSRFToken is null, cannot continue')
|
||||
return
|
||||
}
|
||||
var AssetLikesCount = Number(containerElement.getAttribute("data-likes"))
|
||||
var AssetDislikesCount = Number(containerElement.getAttribute("data-dislikes"))
|
||||
var UserVoteStatus = containerElement.getAttribute("data-uservote-status") // 2 = Dislike, 0 = No vote, 1 = Like
|
||||
|
||||
const LikeButton = containerElement.getElementsByClassName('icon-like')[0]
|
||||
const DislikeButton = containerElement.getElementsByClassName('icon-dislike')[0]
|
||||
const VotePercentageElement = containerElement.getElementsByClassName('votepercentage')[0]
|
||||
const LikesElementText = containerElement.getElementsByClassName('vote-up-text')[0]
|
||||
const DislikesElementText = containerElement.getElementsByClassName('vote-down-text')[0]
|
||||
|
||||
const VoteFeedbackText = containerElement.getElementsByClassName('vote-feedback-text')[0]
|
||||
|
||||
const UpdateVoteCount = async () => {
|
||||
LikesElementText.textContent = AssetLikesCount
|
||||
LikesElementText.setAttribute("title", AssetLikesCount)
|
||||
DislikesElementText.textContent = AssetDislikesCount
|
||||
DislikesElementText.setAttribute("title", AssetDislikesCount)
|
||||
|
||||
const TotalVotes = AssetLikesCount + AssetDislikesCount
|
||||
var LikePercentage = Math.round((AssetLikesCount / TotalVotes) * 100)
|
||||
if ( TotalVotes == 0 ) {
|
||||
LikePercentage = 50
|
||||
} else if ( TotalVotes == 1 ) { // AssetLikesCount / TotalVotes may be Infinity
|
||||
LikePercentage = AssetLikesCount == 1 ? 100 : 0
|
||||
}
|
||||
VotePercentageElement.style.width = `${LikePercentage}%`
|
||||
}
|
||||
const UpdateVoteButtons = async () => {
|
||||
// Check if the "selected" className is present, if so, remove it if it's not the correct one
|
||||
if ( LikeButton.classList.contains('selected') ) {
|
||||
if ( UserVoteStatus != 1 ) {
|
||||
LikeButton.classList.remove('selected')
|
||||
}
|
||||
} else if ( UserVoteStatus == 1 ) {
|
||||
LikeButton.classList.add('selected')
|
||||
}
|
||||
if ( DislikeButton.classList.contains('selected') ) {
|
||||
if ( UserVoteStatus != 2 ) {
|
||||
DislikeButton.classList.remove('selected')
|
||||
}
|
||||
} else if ( UserVoteStatus == 2 ) {
|
||||
DislikeButton.classList.add('selected')
|
||||
}
|
||||
}
|
||||
const UpdateUserVoteStatus = async ( newVoteStatus ) => {
|
||||
var OriginalVoteStatus = UserVoteStatus;
|
||||
var OriginalLikesCount = AssetLikesCount;
|
||||
var OriginalDislikesCount = AssetDislikesCount;
|
||||
let ServerVoteResponse;
|
||||
if ( newVoteStatus == UserVoteStatus ) {
|
||||
return;
|
||||
}
|
||||
UserVoteStatus = newVoteStatus
|
||||
if ( newVoteStatus == 1 ) {
|
||||
AssetLikesCount++
|
||||
if ( OriginalVoteStatus == 2 ) {
|
||||
AssetDislikesCount--
|
||||
}
|
||||
}
|
||||
if ( newVoteStatus == 2 ) {
|
||||
AssetDislikesCount++
|
||||
if ( OriginalVoteStatus == 1 ) {
|
||||
AssetLikesCount--
|
||||
}
|
||||
}
|
||||
if ( newVoteStatus == 0 ) {
|
||||
if ( OriginalVoteStatus == 1 ) {
|
||||
AssetLikesCount--
|
||||
}
|
||||
if ( OriginalVoteStatus == 2 ) {
|
||||
AssetDislikesCount--
|
||||
}
|
||||
}
|
||||
await UpdateVoteButtons()
|
||||
await UpdateVoteCount()
|
||||
|
||||
try {
|
||||
ServerVoteResponse = await fetch(`/vote/${assetId}/${newVoteStatus}`,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': XCSRFToken
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(`Error occured while trying to update user vote: ${error}`)
|
||||
return
|
||||
}
|
||||
if ( ServerVoteResponse.status != 200 ) {
|
||||
console.log(`Server responded with status code ${ServerVoteResponse.status} while trying to update user vote`)
|
||||
UserVoteStatus = OriginalVoteStatus
|
||||
AssetLikesCount = OriginalLikesCount
|
||||
AssetDislikesCount = OriginalDislikesCount
|
||||
VoteFeedbackText.textContent = `Error while trying to update vote, Status: ${ServerVoteResponse.status}`
|
||||
VoteFeedbackText.style.display = 'block'
|
||||
await UpdateVoteButtons()
|
||||
await UpdateVoteCount()
|
||||
return
|
||||
}
|
||||
return;
|
||||
}
|
||||
await UpdateVoteCount()
|
||||
await UpdateVoteButtons()
|
||||
|
||||
LikeButton.addEventListener('click', async () => {
|
||||
// Check if its already selected, if so, remove the vote
|
||||
if ( LikeButton.classList.contains('selected') ) {
|
||||
await UpdateUserVoteStatus(0)
|
||||
return
|
||||
}
|
||||
await UpdateUserVoteStatus(1)
|
||||
})
|
||||
DislikeButton.addEventListener('click', async () => {
|
||||
// Check if its already selected, if so, remove the vote
|
||||
if ( DislikeButton.classList.contains('selected') ) {
|
||||
await UpdateUserVoteStatus(0)
|
||||
return
|
||||
}
|
||||
await UpdateUserVoteStatus(2)
|
||||
})
|
||||
}
|
||||
|
||||
async function initFavoriteContainer( containerElement ) {
|
||||
const assetId = containerElement.getAttribute('data-assetid')
|
||||
const XCSRFToken = document.getElementById('X-CSRF-TOKEN').getAttribute('data-xcsrf')
|
||||
if ( XCSRFToken == null ) {
|
||||
console.log('XCSRFToken is null, cannot continue')
|
||||
return
|
||||
}
|
||||
var FavoriteCount = Number(containerElement.getAttribute("data-favorite-count"))
|
||||
var UserFavoriteStatus = containerElement.getAttribute("data-userfavorite-status") == "True" ? true : false
|
||||
const FavoriteButton = containerElement.getElementsByClassName('icon-favorite')[0]
|
||||
const FavoriteButtonText = containerElement.getElementsByClassName('text-favorite')[0]
|
||||
|
||||
const UpdateFavoriteCount = async () => {
|
||||
FavoriteButtonText.textContent = FavoriteCount
|
||||
FavoriteButtonText.setAttribute("title", FavoriteCount)
|
||||
}
|
||||
const UpdateFavoriteButton = async () => {
|
||||
if ( UserFavoriteStatus ) {
|
||||
FavoriteButton.classList.add('favorited')
|
||||
} else {
|
||||
FavoriteButton.classList.remove('favorited')
|
||||
}
|
||||
}
|
||||
const UpdateUserFavoriteStatus = async ( newFavoriteStatus ) => {
|
||||
var OriginalFavoriteStatus = UserFavoriteStatus;
|
||||
var OriginalFavoriteCount = FavoriteCount;
|
||||
let ServerFavoriteResponse;
|
||||
if ( newFavoriteStatus == UserFavoriteStatus ) {
|
||||
return;
|
||||
}
|
||||
UserFavoriteStatus = newFavoriteStatus
|
||||
if ( newFavoriteStatus ) {
|
||||
FavoriteCount++
|
||||
} else {
|
||||
FavoriteCount--
|
||||
}
|
||||
await UpdateFavoriteButton()
|
||||
await UpdateFavoriteCount()
|
||||
|
||||
try {
|
||||
if ( newFavoriteStatus ) {
|
||||
ServerFavoriteResponse = await fetch(`/favorite/${assetId}`,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': XCSRFToken
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ServerFavoriteResponse = await fetch(`/favorite/${assetId}`,{
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': XCSRFToken
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`Error occured while trying to update user favorite: ${error}`)
|
||||
return
|
||||
}
|
||||
if ( ServerFavoriteResponse.status != 200 ) {
|
||||
console.log(`Server responded with status code ${ServerFavoriteResponse.status} while trying to update user favorite`)
|
||||
UserFavoriteStatus = OriginalFavoriteStatus
|
||||
FavoriteCount = OriginalFavoriteCount
|
||||
await UpdateFavoriteButton()
|
||||
await UpdateFavoriteCount()
|
||||
return
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await UpdateFavoriteButton()
|
||||
await UpdateFavoriteCount()
|
||||
|
||||
FavoriteButton.addEventListener('click', async () => {
|
||||
await UpdateUserFavoriteStatus(!UserFavoriteStatus)
|
||||
})
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const assetRateContainers = document.getElementsByClassName('usersVote')
|
||||
for(let i = 0; i < assetRateContainers.length; i++){
|
||||
await initVoteContainer( assetRateContainers[i] )
|
||||
}
|
||||
const assetFavoriteContainers = document.getElementsByClassName('favorite-button-container')
|
||||
for(let i = 0; i < assetFavoriteContainers.length; i++){
|
||||
await initFavoriteContainer( assetFavoriteContainers[i] )
|
||||
}
|
||||
})
|
||||
Vendored
+7
File diff suppressed because one or more lines are too long
@@ -0,0 +1,153 @@
|
||||
/* Functions used to buy or take assets */
|
||||
|
||||
function buyAsset(assetId, assetName, expectedPrice, currencyType){
|
||||
const PurchaseModal = new bootstrap.Modal(document.getElementById('purchaseModal'), { keyboard: false })
|
||||
const purchaseModalContent = document.getElementById('purchase-modal-content')
|
||||
const purchaseModalTitle = document.getElementById('purchase-modal-title')
|
||||
const purchaseModalButton = document.getElementById('purchase-modal-btn')
|
||||
const purchaseModalClose = document.getElementById('purchase-modal-close')
|
||||
|
||||
const csrfToken = document.getElementById('csrf_token').getAttribute('data-csrf-token')
|
||||
|
||||
purchaseModalTitle.textContent = `Confirm purchase of ${assetName}`
|
||||
purchaseModalContent.textContent = `Are you sure you want to buy ${assetName} for ${expectedPrice == 0 ? 'Free' : expectedPrice}${expectedPrice != 0 ? (currencyType == 0 ? " Robux" : " Tix") : ''}?`
|
||||
|
||||
purchaseModalButton.onclick = () => {
|
||||
purchaseModalButton.disabled = true
|
||||
purchaseModalClose.disabled = true
|
||||
purchaseModalContent.textContent = `Processing purchase...`
|
||||
fetch(`/catalog/api/purchase`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
assetId: Number(assetId),
|
||||
expectedPrice: Number(expectedPrice),
|
||||
currencyType: Number(currencyType)
|
||||
})
|
||||
}).then(response => response.json()).then(data => {
|
||||
if(data.success){
|
||||
window.location.reload()
|
||||
}else{
|
||||
purchaseModalContent.textContent = `There was an issue processing your purchase, please try again later. Error: ${data.message}`
|
||||
}
|
||||
}).catch(error => {
|
||||
purchaseModalContent.textContent = `There was an issue processing your purchase, please try again later. Error: ${error}`
|
||||
})
|
||||
}
|
||||
purchaseModalButton.disabled = false
|
||||
purchaseModalClose.disabled = false
|
||||
PurchaseModal.show()
|
||||
}
|
||||
|
||||
async function PurchaseLimitedOffer( assetId, assetName, expectedPrice, expectedOwner, itemOwnershipId ) {
|
||||
const PurchaseModal = new bootstrap.Modal(document.getElementById('purchaseModal'), { keyboard: false })
|
||||
const purchaseModalContent = document.getElementById('purchase-modal-content')
|
||||
const purchaseModalTitle = document.getElementById('purchase-modal-title')
|
||||
const purchaseModalButton = document.getElementById('purchase-modal-btn')
|
||||
const purchaseModalClose = document.getElementById('purchase-modal-close')
|
||||
|
||||
const csrfToken = document.getElementById('csrf_token').getAttribute('data-csrf-token')
|
||||
|
||||
purchaseModalTitle.textContent = `Confirm purchase of ${assetName}`
|
||||
purchaseModalContent.textContent = `Are you sure you want to buy ${assetName} for R$${expectedPrice}?`
|
||||
|
||||
purchaseModalButton.onclick = async () => {
|
||||
purchaseModalButton.disabled = true
|
||||
purchaseModalClose.disabled = true
|
||||
purchaseModalContent.textContent = `Processing purchase...`
|
||||
var LimitedPurchaseResponse = await fetch("/catalog/api/purchase-limited", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
assetId: Number(assetId),
|
||||
expectedPrice: Number(expectedPrice),
|
||||
expectedOwner: Number(expectedOwner),
|
||||
itemOwnershipId: Number(itemOwnershipId)
|
||||
})
|
||||
})
|
||||
var LimitedPurchaseResponseJson = await LimitedPurchaseResponse.json()
|
||||
if(LimitedPurchaseResponseJson.success){
|
||||
window.location.reload()
|
||||
} else {
|
||||
purchaseModalContent.textContent = `There was an issue processing your purchase, please try again later. Error: ${LimitedPurchaseResponseJson.message}`
|
||||
}
|
||||
}
|
||||
purchaseModalButton.disabled = false
|
||||
purchaseModalClose.disabled = false
|
||||
PurchaseModal.show()
|
||||
}
|
||||
|
||||
function updateOffsaleCountdown( offsaleAt ) {
|
||||
var offsaleElement = document.getElementById('offsale-countdown')
|
||||
if (!offsaleElement) {
|
||||
console.warn("Could not find offsale countdown element")
|
||||
return
|
||||
}
|
||||
var timeLeft = offsaleAt - new Date()
|
||||
if (timeLeft <= 0) {
|
||||
return
|
||||
}
|
||||
var hours = Math.floor(timeLeft / 1000 / 60 / 60)
|
||||
var minutes = Math.floor(timeLeft / 1000 / 60) % 60
|
||||
var seconds = Math.floor(timeLeft / 1000) % 60
|
||||
offsaleElement.textContent = `${hours}:${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}`
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const AssetInfoMetaTag = document.getElementById('asset-info')
|
||||
var AssetId = null
|
||||
var DoesUserOwnAset = false
|
||||
var AssetName = ""
|
||||
var isAssetLimited = false
|
||||
var isAssetOnsale = true
|
||||
var offsaleAt = null
|
||||
if(AssetInfoMetaTag){
|
||||
AssetId = AssetInfoMetaTag.getAttribute('data-asset-id')
|
||||
AssetName = AssetInfoMetaTag.getAttribute('data-asset-name')
|
||||
DoesUserOwnAset = AssetInfoMetaTag.getAttribute('data-user-ownasset')
|
||||
DoesUserOwnAset = DoesUserOwnAset == "true" ? true : false
|
||||
isAssetLimited = AssetInfoMetaTag.getAttribute('data-islimited')
|
||||
isAssetLimited = isAssetLimited == "true" ? true : false
|
||||
isAssetOnsale = AssetInfoMetaTag.getAttribute('data-asset-onsale')
|
||||
isAssetOnsale = isAssetOnsale == "true" ? true : false
|
||||
offsaleAt = AssetInfoMetaTag.getAttribute('data-offsale')
|
||||
if(offsaleAt != null){
|
||||
offsaleAt = new Date(offsaleAt * 1000)
|
||||
//offsaleAt = Date.UTC(offsaleAt.getFullYear(), offsaleAt.getMonth(), offsaleAt.getDate(), offsaleAt.getHours(), offsaleAt.getMinutes(), offsaleAt.getSeconds())
|
||||
//offsaleAt = new Date(offsaleAt)
|
||||
}
|
||||
}
|
||||
|
||||
if (offsaleAt != null ){
|
||||
updateOffsaleCountdown(offsaleAt)
|
||||
setInterval(() => {
|
||||
updateOffsaleCountdown(offsaleAt)
|
||||
}, 1000)
|
||||
}
|
||||
const PurchaseButtons = document.getElementsByClassName('purchase-button')
|
||||
for(let i = 0; i < PurchaseButtons.length; i++){
|
||||
if (!DoesUserOwnAset || (isAssetLimited && !isAssetOnsale)) {
|
||||
if (!isAssetLimited || isAssetOnsale) {
|
||||
PurchaseButtons[i].onclick = () => {
|
||||
if ( !AssetInfoMetaTag ) {
|
||||
buyAsset(PurchaseButtons[i].getAttribute('data-asset-id'), PurchaseButtons[i].getAttribute('data-asset-name'), PurchaseButtons[i].getAttribute('data-expected-price'), PurchaseButtons[i].getAttribute('data-currency-type'))
|
||||
} else {
|
||||
buyAsset(AssetId, AssetName, PurchaseButtons[i].getAttribute('data-expected-price'), PurchaseButtons[i].getAttribute('data-currency-type'))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PurchaseButtons[i].onclick = async () => {
|
||||
await PurchaseLimitedOffer(AssetId, AssetName, PurchaseButtons[i].getAttribute('data-expected-price'), PurchaseButtons[i].getAttribute('data-expectedowner'), PurchaseButtons[i].getAttribute('data-expectedid'))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PurchaseButtons[i].setAttribute("class", PurchaseButtons[i].getAttribute("class").replace("purchase-button", "purchase-button disabled"))
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const toggleBtns = document.querySelectorAll('.toggle-sidebar'); // all toggle buttons
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
|
||||
toggleBtns.forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
sidebar.classList.toggle('show');
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (
|
||||
window.innerWidth <= 992 &&
|
||||
sidebar.classList.contains('show') &&
|
||||
!sidebar.contains(e.target) &&
|
||||
!Array.from(toggleBtns).some(btn => btn.contains(e.target))
|
||||
) {
|
||||
sidebar.classList.remove('show');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
function abbreviateNumber(value) {
|
||||
value = parseInt(value);
|
||||
if (value >= 1e9) return (value / 1e9).toFixed(1).replace(/\.0$/, '') + 'B';
|
||||
if (value >= 1e6) return (value / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
|
||||
if (value >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, '') + 'K';
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const robuxEl = document.getElementById("robux-amount");
|
||||
const tixEl = document.getElementById("tix-amount");
|
||||
|
||||
if (robuxEl) {
|
||||
const rawRobux = robuxEl.textContent.trim();
|
||||
robuxEl.textContent = abbreviateNumber(rawRobux);
|
||||
}
|
||||
|
||||
if (tixEl) {
|
||||
const rawTix = tixEl.textContent.trim();
|
||||
tixEl.textContent = abbreviateNumber(rawTix);
|
||||
}
|
||||
});
|
||||
|
||||
const modal = document.getElementById('purchaseModal');
|
||||
if (modal && modal.parentNode !== document.body) {
|
||||
document.body.appendChild(modal);
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (window.innerWidth <= 768) {
|
||||
const footer = document.getElementById('footer');
|
||||
if (footer) {
|
||||
footer.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
function heartbeat() {
|
||||
fetch('/v1/heartbeat')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success !== "true") {
|
||||
location.reload();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
heartbeat();
|
||||
setInterval(heartbeat, 15000);
|
||||
@@ -0,0 +1,110 @@
|
||||
async function initalizeComponent( memberElement ) {
|
||||
const GroupId = Number(memberElement.getAttribute('data-groupid'))
|
||||
const RoleSelectElement = memberElement.getElementsByClassName('members-select-role')[0]
|
||||
|
||||
const PaginationBackBtn = memberElement.getElementsByClassName('pagination-back-btn')[0]
|
||||
const PaginationTextElement = memberElement.getElementsByClassName('pagination-page-number')[0]
|
||||
const PaginationNextBtn = memberElement.getElementsByClassName('pagination-next-btn')[0]
|
||||
|
||||
const UserCardTemplate = document.getElementsByClassName('user-card-template')[0]
|
||||
const UserCardContainer = memberElement.getElementsByClassName('user-card-container')[0]
|
||||
|
||||
var SelectedRoleId = 0
|
||||
var CurrentPage = 1
|
||||
|
||||
if (RoleSelectElement.options.length > 0) {
|
||||
SelectedRoleId = RoleSelectElement.options[0].value
|
||||
} else {
|
||||
console.error('No role found in RoleSelectElement')
|
||||
return;
|
||||
}
|
||||
|
||||
async function getPageResult( RolesetId, PageNumber ) {
|
||||
try {
|
||||
const response = await fetch(`/groups/members_json/${GroupId}?role=${RolesetId}&page=${PageNumber}`)
|
||||
const result = await response.json()
|
||||
return result
|
||||
} catch (error) {
|
||||
if (error.status == 429) {
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
return await getPageResult( RolesetId, PageNumber )
|
||||
} else {
|
||||
console.error(error)
|
||||
alert('An error occured while trying to get the page result, please try again later. Status: ' + error.status)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function CreateUserCard( UserId, Username ) {
|
||||
const UserCard = UserCardTemplate.cloneNode(true)
|
||||
const UserCardUsername = UserCard.getElementsByClassName('user-name')[0]
|
||||
const UserCardAvatar = UserCard.getElementsByClassName('avatar-img')[0]
|
||||
|
||||
UserCardUsername.innerText = Username
|
||||
UserCardAvatar.src = `/Thumbs/Avatar.ashx?userId=${UserId}&x=100&y=100`
|
||||
|
||||
UserCard.style.display = 'block'
|
||||
UserCard.classList.remove('user-card-template')
|
||||
UserCard.href = `/users/${UserId}/profile`
|
||||
UserCardContainer.appendChild(UserCard)
|
||||
}
|
||||
|
||||
async function updatePage( RolesetId, PageNumber ) {
|
||||
PaginationNextBtn.disabled = true
|
||||
PaginationBackBtn.disabled = true
|
||||
UserCardContainer.innerHTML = ''
|
||||
|
||||
const result = await getPageResult( RolesetId, PageNumber )
|
||||
const Users = result.users
|
||||
|
||||
PaginationTextElement.innerText = `Page ${PageNumber}`
|
||||
if (PageNumber == 1) {
|
||||
PaginationBackBtn.disabled = true
|
||||
} else {
|
||||
PaginationBackBtn.disabled = false
|
||||
}
|
||||
|
||||
if (result.nextpage) {
|
||||
PaginationNextBtn.disabled = false
|
||||
} else {
|
||||
PaginationNextBtn.disabled = true
|
||||
}
|
||||
for (let i = 0; i < Users.length; i++) {
|
||||
const User = Users[i]
|
||||
await CreateUserCard( User.userId, User.username )
|
||||
}
|
||||
if ( Users.length == 0 ) {
|
||||
const NoUsersElement = document.createElement('p')
|
||||
NoUsersElement.innerText = 'No users found'
|
||||
NoUsersElement.className = 'w-100 text-center mt-auto mb-auto'
|
||||
UserCardContainer.appendChild(NoUsersElement)
|
||||
}
|
||||
}
|
||||
|
||||
RoleSelectElement.addEventListener('change', async () => {
|
||||
SelectedRoleId = RoleSelectElement.value
|
||||
CurrentPage = 1
|
||||
await updatePage( SelectedRoleId, 1 )
|
||||
})
|
||||
|
||||
PaginationBackBtn.addEventListener('click', async () => {
|
||||
CurrentPage--
|
||||
await updatePage( SelectedRoleId, CurrentPage )
|
||||
})
|
||||
|
||||
PaginationNextBtn.addEventListener('click', async () => {
|
||||
CurrentPage++
|
||||
await updatePage( SelectedRoleId, CurrentPage )
|
||||
})
|
||||
|
||||
await updatePage( SelectedRoleId, CurrentPage )
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const MemberElements = document.getElementsByClassName('group-member-list')
|
||||
for (let i = 0; i < MemberElements.length; i++) {
|
||||
const MemberElement = MemberElements[i]
|
||||
await initalizeComponent( MemberElement )
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,369 @@
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const TradeInfoElement = document.getElementById('trade-info')
|
||||
if ( TradeInfoElement == null ) return
|
||||
|
||||
const RequesterUserId = Number(TradeInfoElement.getAttribute('data-requester-userid'))
|
||||
const TargetUserId = Number(TradeInfoElement.getAttribute('data-target-userid'))
|
||||
const XCSRFToken = TradeInfoElement.getAttribute('data-xcsrf-token')
|
||||
const isTOTPEnabled = TradeInfoElement.getAttribute('data-totp-enabled') == 'True'
|
||||
|
||||
const RequesterInventoryElement = document.getElementById('requester-inventory-container')
|
||||
const TargetInventoryElement = document.getElementById('target-inventory-container')
|
||||
|
||||
const ItemCardTemplate = document.getElementById('item-card-template')
|
||||
ItemCardTemplate.id = ''
|
||||
|
||||
var UAIDInfo = {}
|
||||
var RequesterOffer = []
|
||||
var TargetOffer = []
|
||||
|
||||
const RequesterItemOfferContainer = document.getElementById('requester-item-offer-container')
|
||||
const TargetItemOfferContainer = document.getElementById('target-item-offer-container')
|
||||
|
||||
const TargetOfferValueText = document.getElementById('target-offer-value')
|
||||
const RequesterOfferValueText = document.getElementById('requester-offer-value')
|
||||
const TargetOfferRobuxInput = document.getElementById('target-offer-robux-input')
|
||||
const RequesterOfferRobuxInput = document.getElementById('requester-offer-robux-input')
|
||||
|
||||
const TradeSumbitButton = document.getElementById('trade-submit-btn')
|
||||
const TOTPInputElement = document.getElementById('otp-code-input')
|
||||
|
||||
if ( isTOTPEnabled ) {
|
||||
TOTPInputElement.addEventListener('input', async () => {
|
||||
if ( TOTPInputElement.value.length > 6 ) {
|
||||
TOTPInputElement.value = TOTPInputElement.value.slice(0, 6)
|
||||
}
|
||||
await formValidation()
|
||||
})
|
||||
TOTPInputElement.style.display = 'block'
|
||||
}
|
||||
const TransparentBackgroundTop = document.getElementById('transparent-background-top')
|
||||
const SubmitButtonFeedback = document.getElementById('submit-btn-feedback')
|
||||
|
||||
var isAlreadySubmitting = false
|
||||
const submitTradeRequest = async () => {
|
||||
if (TradeSumbitButton.disabled) return
|
||||
if ( isAlreadySubmitting ) return
|
||||
isAlreadySubmitting = true
|
||||
TradeSumbitButton.disabled = true
|
||||
TransparentBackgroundTop.style.display = 'block'
|
||||
SubmitButtonFeedback.style.display = 'none'
|
||||
|
||||
const RequesterOfferRobux = Number(RequesterOfferRobuxInput.value) || 0
|
||||
const TargetOfferRobux = Number(TargetOfferRobuxInput.value) || 0
|
||||
const RequesterOfferUAIDs = RequesterOffer
|
||||
const TargetOfferUAIDs = TargetOffer
|
||||
|
||||
const TradeRequestResponse = await fetch(`/trade/${TargetUserId}/create`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': XCSRFToken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"RequesterOfferRobux": RequesterOfferRobux,
|
||||
"TargetOfferRobux": TargetOfferRobux,
|
||||
"RequesterOfferUAIDs": RequesterOfferUAIDs,
|
||||
"TargetOfferUAIDs": TargetOfferUAIDs,
|
||||
"TOTPCode": isTOTPEnabled ? Number(TOTPInputElement.value) : null
|
||||
})
|
||||
})
|
||||
let TradeRequestResponseJSON
|
||||
try {
|
||||
TradeRequestResponseJSON = await TradeRequestResponse.json()
|
||||
} catch (e) {
|
||||
SubmitButtonFeedback.textContent = `${TradeRequestResponse.status}: An error occurred while submitting the trade request.`
|
||||
SubmitButtonFeedback.style.display = 'block'
|
||||
TradeSumbitButton.disabled = false
|
||||
TransparentBackgroundTop.style.display = 'none'
|
||||
isAlreadySubmitting = false
|
||||
return
|
||||
}
|
||||
if ( TradeRequestResponse.status != 200 ) {
|
||||
SubmitButtonFeedback.textContent = `${TradeRequestResponse.status}: ${TradeRequestResponseJSON.message}`
|
||||
SubmitButtonFeedback.style.display = 'block'
|
||||
TradeSumbitButton.disabled = false
|
||||
TransparentBackgroundTop.style.display = 'none'
|
||||
isAlreadySubmitting = false
|
||||
return
|
||||
}
|
||||
window.location.href = `/trade/view/${TradeRequestResponseJSON.tradeId}`
|
||||
}
|
||||
|
||||
const formValidation = async () => {
|
||||
if ( RequesterOffer.length == 0 || TargetOffer.length == 0 ) {
|
||||
TradeSumbitButton.disabled = true
|
||||
return
|
||||
}
|
||||
if ( RequesterOffer.length > 4 || TargetOffer.length > 4 ) {
|
||||
TradeSumbitButton.disabled = true
|
||||
return
|
||||
}
|
||||
if ( isTOTPEnabled && TOTPInputElement.value.length != 6 ) {
|
||||
TradeSumbitButton.disabled = true
|
||||
return
|
||||
}
|
||||
TradeSumbitButton.disabled = false
|
||||
}
|
||||
|
||||
const UpdateOfferValue = async () => {
|
||||
var RequesterOfferValue = 0
|
||||
var TargetOfferValue = 0
|
||||
|
||||
RequesterOffer.forEach(ItemUAID => {
|
||||
RequesterOfferValue += UAIDInfo[ItemUAID].rap
|
||||
})
|
||||
TargetOffer.forEach(ItemUAID => {
|
||||
TargetOfferValue += UAIDInfo[ItemUAID].rap
|
||||
})
|
||||
|
||||
RequesterOfferValue += Number(RequesterOfferRobuxInput.value)
|
||||
TargetOfferValue += Number(TargetOfferRobuxInput.value)
|
||||
|
||||
TargetOfferValueText.textContent = `R$ ${TargetOfferValue}`
|
||||
RequesterOfferValueText.textContent = `R$ ${RequesterOfferValue}`
|
||||
await formValidation()
|
||||
}
|
||||
|
||||
TargetOfferRobuxInput.addEventListener('input', async () => {
|
||||
if ( Number(TargetOfferRobuxInput.value) < 0 ) {
|
||||
TargetOfferRobuxInput.value = 0
|
||||
}
|
||||
if ( Number(TargetOfferRobuxInput.value) > 100000 ) {
|
||||
TargetOfferRobuxInput.value = 100000
|
||||
}
|
||||
await UpdateOfferValue()
|
||||
})
|
||||
RequesterOfferRobuxInput.addEventListener('input', async () => {
|
||||
if ( Number(RequesterOfferRobuxInput.value) < 0 ) {
|
||||
RequesterOfferRobuxInput.value = 0
|
||||
}
|
||||
if ( Number(RequesterOfferRobuxInput.value) > 100000 ) {
|
||||
RequesterOfferRobuxInput.value = 100000
|
||||
}
|
||||
await UpdateOfferValue()
|
||||
})
|
||||
|
||||
const ReloadOfferImages = async () => {
|
||||
const RequesterOfferChildren = RequesterItemOfferContainer.children
|
||||
for ( let i = 0; i < RequesterOfferChildren.length; i++ ){
|
||||
const ItemCard = RequesterOfferChildren[i]
|
||||
const ItemCardImage = ItemCard.querySelector('.item-image')
|
||||
if (RequesterOffer[i] == null) {
|
||||
ItemCardImage.src = ''
|
||||
ItemCardImage.alt = ''
|
||||
ItemCardImage.style.display = 'none'
|
||||
ItemCard.style.cursor = 'default'
|
||||
ItemCardImage.onclick = null
|
||||
continue
|
||||
} else {
|
||||
if (ItemCardImage.classList.contains('d-none')) {
|
||||
ItemCardImage.classList.remove('d-none')
|
||||
}
|
||||
ItemCard.style.cursor = 'pointer'
|
||||
ItemCardImage.style.display = 'block'
|
||||
ItemCardImage.src = `/Thumbs/Asset.ashx?x=100&y=100&assetId=${UAIDInfo[RequesterOffer[i]].assetId}`
|
||||
ItemCardImage.onclick = async () => {
|
||||
await RemoveItemFromOffer(RequesterUserId, RequesterOffer[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TargetOfferChildren = TargetItemOfferContainer.children
|
||||
for ( let i = 0; i < TargetOfferChildren.length; i++ ){
|
||||
const ItemCard = TargetOfferChildren[i]
|
||||
const ItemCardImage = ItemCard.querySelector('.item-image')
|
||||
if (TargetOffer[i] == null) {
|
||||
ItemCardImage.src = ''
|
||||
ItemCardImage.alt = ''
|
||||
ItemCardImage.style.display = 'none'
|
||||
ItemCard.style.cursor = 'default'
|
||||
ItemCardImage.onclick = null
|
||||
continue
|
||||
} else {
|
||||
if (ItemCardImage.classList.contains('d-none')) {
|
||||
ItemCardImage.classList.remove('d-none')
|
||||
}
|
||||
ItemCard.style.cursor = 'pointer'
|
||||
ItemCardImage.style.display = 'block'
|
||||
ItemCardImage.src = `/Thumbs/Asset.ashx?x=100&y=100&assetId=${UAIDInfo[TargetOffer[i]].assetId}`
|
||||
ItemCardImage.onclick = async () => {
|
||||
await RemoveItemFromOffer(TargetUserId, TargetOffer[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
await UpdateOfferValue()
|
||||
}
|
||||
|
||||
const AddItemToOffer = async ( UserId, ItemUAID ) => {
|
||||
if ( UserId == RequesterUserId ) {
|
||||
if ( RequesterOffer.includes(ItemUAID) ) return
|
||||
if ( RequesterOffer.length >= 4 ) {
|
||||
const RemovedItemUAID = RequesterOffer[0]
|
||||
await RemoveItemFromOffer(RequesterUserId, RemovedItemUAID)
|
||||
}
|
||||
RequesterOffer.push(ItemUAID)
|
||||
}
|
||||
if ( UserId == TargetUserId ) {
|
||||
if ( TargetOffer.includes(ItemUAID) ) return
|
||||
if ( TargetOffer.length >= 4 ) {
|
||||
const RemovedItemUAID = TargetOffer[0]
|
||||
await RemoveItemFromOffer(TargetUserId, RemovedItemUAID)
|
||||
}
|
||||
TargetOffer.push(ItemUAID)
|
||||
}
|
||||
const AllItemCards = document.querySelectorAll('.item-card')
|
||||
AllItemCards.forEach(ItemCard => {
|
||||
const ItemCardUAID = ItemCard.getAttribute('data-item-uaid')
|
||||
if ( ItemCardUAID == ItemUAID ) {
|
||||
const ItemCardImage = ItemCard.querySelector('.item-card-image')
|
||||
ItemCardImage.classList.add("border-primary")
|
||||
}
|
||||
})
|
||||
await ReloadOfferImages()
|
||||
}
|
||||
|
||||
const RemoveItemFromOffer = async ( UserId, ItemUAID ) => {
|
||||
if ( UserId == RequesterUserId ) {
|
||||
if ( !RequesterOffer.includes(ItemUAID) ) return
|
||||
RequesterOffer.splice(RequesterOffer.indexOf(ItemUAID), 1)
|
||||
}
|
||||
if ( UserId == TargetUserId ) {
|
||||
if ( !TargetOffer.includes(ItemUAID) ) return
|
||||
TargetOffer.splice(TargetOffer.indexOf(ItemUAID), 1)
|
||||
}
|
||||
const AllItemCards = document.querySelectorAll('.item-card')
|
||||
AllItemCards.forEach(ItemCard => {
|
||||
const ItemCardUAID = ItemCard.getAttribute('data-item-uaid')
|
||||
if ( ItemCardUAID == ItemUAID ) {
|
||||
const ItemCardImage = ItemCard.querySelector('.item-card-image')
|
||||
if ( ItemCardImage.classList.contains("border-primary") ){
|
||||
ItemCardImage.classList.remove("border-primary")
|
||||
}
|
||||
}
|
||||
})
|
||||
await ReloadOfferImages()
|
||||
}
|
||||
|
||||
const LoadInventoryPage = async ( UserId, InventoryElement, PageNumber ) => {
|
||||
InventoryElement.innerHTML = ''
|
||||
const ParentElement = InventoryElement.parentElement
|
||||
const PaginationBackBtn = ParentElement.querySelector('.pagination-back-btn')
|
||||
const PaginationNextBtn = ParentElement.querySelector('.pagination-next-btn')
|
||||
const PaginationPageNumber = ParentElement.querySelector('.pagination-page-number')
|
||||
|
||||
PaginationBackBtn.disabled = true
|
||||
PaginationNextBtn.disabled = true
|
||||
PaginationPageNumber.textContent = `Page ${PageNumber}`
|
||||
|
||||
const InventoryResposne = await fetch(`/trade/${UserId}/inventory?page=${PageNumber}`)
|
||||
if ( !InventoryResposne.ok ) return
|
||||
const InventoryData = await InventoryResposne.json()
|
||||
|
||||
InventoryData.data.forEach(Item => {
|
||||
const NewItemCard = ItemCardTemplate.cloneNode(true)
|
||||
NewItemCard.setAttribute('data-item-assetid', Item.id)
|
||||
NewItemCard.setAttribute('data-item-name', Item.name)
|
||||
NewItemCard.setAttribute('data-item-uaid', Item.uaid)
|
||||
NewItemCard.setAttribute('data-item-serial', Item.serialNumber)
|
||||
NewItemCard.setAttribute('data-item-rap', Item.rap)
|
||||
NewItemCard.classList.add('item-card')
|
||||
|
||||
const ItemCardImage = NewItemCard.querySelector('.item-card-image')
|
||||
ItemCardImage.src = `/Thumbs/Asset.ashx?x=100&y=100&assetId=${Item.id}`
|
||||
ItemCardImage.alt = Item.name
|
||||
|
||||
const ItemCardName = NewItemCard.querySelector('.item-card-name')
|
||||
ItemCardName.textContent = Item.name
|
||||
ItemCardName.href = `/catalog/${Item.id}/`
|
||||
|
||||
const ItemCardSerial = NewItemCard.querySelector('.item-card-serial')
|
||||
if (Item.serialNumber != null) {
|
||||
ItemCardSerial.textContent = `#${Item.serialNumber}`
|
||||
} else {
|
||||
ItemCardSerial.remove()
|
||||
}
|
||||
NewItemCard.style.display = 'block'
|
||||
InventoryElement.appendChild(NewItemCard)
|
||||
|
||||
UAIDInfo[Item.uaid] = {
|
||||
'assetId': Item.id,
|
||||
'serialNumber': Item.serialNumber,
|
||||
'rap': Item.rap,
|
||||
'name': Item.name,
|
||||
'ownerId': UserId,
|
||||
}
|
||||
if ( UserId == RequesterUserId ) {
|
||||
if ( RequesterOffer.includes(Item.uaid) ) {
|
||||
ItemCardImage.classList.add("border-primary")
|
||||
}
|
||||
}
|
||||
if ( UserId == TargetUserId ) {
|
||||
if ( TargetOffer.includes(Item.uaid) ) {
|
||||
ItemCardImage.classList.add("border-primary")
|
||||
}
|
||||
}
|
||||
ItemCardImage.style.cursor = 'pointer'
|
||||
ItemCardImage.addEventListener('click', () => {
|
||||
if ( ItemCardImage.classList.contains("border-primary") ){
|
||||
RemoveItemFromOffer(UserId, Item.uaid)
|
||||
return
|
||||
}
|
||||
AddItemToOffer(UserId, Item.uaid)
|
||||
})
|
||||
})
|
||||
if ( InventoryData.data.length == 0 ){
|
||||
const NoItemsMessage = document.createElement('p')
|
||||
NoItemsMessage.className = "text-secondary text-center mt-5 mb-5 w-100"
|
||||
NoItemsMessage.textContent = "User does not have any tradable items"
|
||||
InventoryElement.appendChild(NoItemsMessage)
|
||||
}
|
||||
|
||||
PaginationBackBtn.disabled = PageNumber <= 1
|
||||
PaginationNextBtn.disabled = !InventoryData.nextPage
|
||||
}
|
||||
|
||||
await LoadInventoryPage(RequesterUserId, RequesterInventoryElement, 1)
|
||||
await LoadInventoryPage(TargetUserId, TargetInventoryElement, 1)
|
||||
|
||||
var RequesterPageNumber = 1
|
||||
const RequesterPaginationBackBtn = RequesterInventoryElement.parentElement.querySelector('.pagination-back-btn')
|
||||
const RequesterPaginationNextBtn = RequesterInventoryElement.parentElement.querySelector('.pagination-next-btn')
|
||||
|
||||
var TargetPageNumber = 1
|
||||
const TargetPaginationBackBtn = TargetInventoryElement.parentElement.querySelector('.pagination-back-btn')
|
||||
const TargetPaginationNextBtn = TargetInventoryElement.parentElement.querySelector('.pagination-next-btn')
|
||||
|
||||
RequesterPaginationBackBtn.addEventListener('click', () => {
|
||||
if ( RequesterPaginationBackBtn.disabled ) return
|
||||
if ( RequesterPageNumber <= 1 ) { RequesterPaginationBackBtn.disabled = true; return }
|
||||
RequesterPageNumber--
|
||||
LoadInventoryPage(RequesterUserId, RequesterInventoryElement, RequesterPageNumber)
|
||||
})
|
||||
|
||||
RequesterPaginationNextBtn.addEventListener('click', () => {
|
||||
if ( RequesterPaginationNextBtn.disabled ) return
|
||||
RequesterPageNumber++
|
||||
LoadInventoryPage(RequesterUserId, RequesterInventoryElement, RequesterPageNumber)
|
||||
})
|
||||
|
||||
TargetPaginationBackBtn.addEventListener('click', () => {
|
||||
if ( TargetPaginationBackBtn.disabled ) return
|
||||
if ( TargetPageNumber <= 1 ) { TargetPaginationBackBtn.disabled = true; return }
|
||||
TargetPageNumber--
|
||||
LoadInventoryPage(TargetUserId, TargetInventoryElement, TargetPageNumber)
|
||||
})
|
||||
|
||||
TargetPaginationNextBtn.addEventListener('click', () => {
|
||||
if ( TargetPaginationNextBtn.disabled ) return
|
||||
TargetPageNumber++
|
||||
LoadInventoryPage(TargetUserId, TargetInventoryElement, TargetPageNumber)
|
||||
})
|
||||
|
||||
TradeSumbitButton.addEventListener('click', async () => {
|
||||
if ( TradeSumbitButton.disabled ) return
|
||||
await submitTradeRequest()
|
||||
})
|
||||
|
||||
await formValidation()
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
setInterval(function() {
|
||||
if (document.hasFocus()) {
|
||||
fetch('/presence')
|
||||
}
|
||||
}, 50000);
|
||||
@@ -0,0 +1,15 @@
|
||||
console.log(
|
||||
"%cSTOP!",
|
||||
"color: #5BCEFA; font-size: 80px; font-weight: bold; text-shadow: 2px 2px 0 #F5A9B8, 4px 4px 0 #ffffff;"
|
||||
);
|
||||
|
||||
console.log(
|
||||
"%cIf you are being told to paste something here, there is a 100% chance you are being scammed.\nPlease exit out and report this bad actor to the Discord.\n",
|
||||
"color: #F5A9B8; font-size: 18px; font-weight: 500;"
|
||||
);
|
||||
|
||||
console.log("Remember, trans rights are human rights!")
|
||||
twemoji.parse(
|
||||
document.body,
|
||||
{ base: 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/' }
|
||||
)
|
||||
Reference in New Issue
Block a user