The + and - button shown on item card hover now updates depending on if the item is being worn or not.
409 lines
No EOL
15 KiB
JavaScript
Executable file
409 lines
No EOL
15 KiB
JavaScript
Executable file
setTimeout(function () {}, 100)
|
|
const UserID = JSON.parse(window.localStorage.getItem('account_info')).ID
|
|
|
|
let PageContainer = document.querySelector('.container.p-0.p-lg-5')
|
|
let ItemGrid;
|
|
let Wearing;
|
|
let Tabs;
|
|
let IFrame;
|
|
let TabSelected = 'hat'
|
|
let Search;
|
|
let Page = 1
|
|
let Avatar = {
|
|
"useCharacter": true,
|
|
"items": [
|
|
24122
|
|
],
|
|
"shirt": 24118,
|
|
"pants": 24123,
|
|
"headColor": "#e0e0e0",
|
|
"torsoColor": "#e0e0e0",
|
|
"leftArmColor": "#e0e0e0",
|
|
"rightArmColor": "#e0e0e0",
|
|
"leftLegColor": "#e0e0e0",
|
|
"rightLegColor": "#e0e0e0"
|
|
}
|
|
|
|
if (new URLSearchParams(new URL(window.location).search).get('sandbox') === 'true') {
|
|
console.log('Avatar Sandbox!')
|
|
|
|
LoadFile(chrome.runtime.getURL('js/resources/avatar-sandbox.html'), function(html){
|
|
PageContainer.innerHTML = html
|
|
ItemGrid = document.getElementById('inventory')
|
|
Wearing = document.getElementById('wearing')
|
|
Tabs = document.getElementById('tabs')
|
|
IFrame = document.getElementById('viewFrame')
|
|
|
|
Search = document.getElementById('item-search')
|
|
Search.addEventListener('onchange', function(){
|
|
RefreshItems()
|
|
});
|
|
|
|
UpdateAvatar()
|
|
RefreshItems()
|
|
LoadWearing()
|
|
|
|
Array.from(Tabs.children).forEach(element => {
|
|
element.addEventListener('click', function(){
|
|
let Link = element.getElementsByTagName('a')[0]
|
|
if (!(Link.classList.contains('active'))) {
|
|
Link.classList.add('active')
|
|
Tabs.querySelector(`[data-tab="${TabSelected}"]`).classList.remove('active')
|
|
TabSelected = Link.getAttribute('data-tab')
|
|
Page = 1
|
|
RefreshItems()
|
|
}
|
|
});
|
|
});
|
|
|
|
let Clear = document.getElementById('clear')
|
|
Clear.addEventListener('click', function(){
|
|
Avatar = {
|
|
"useCharacter": true,
|
|
"items": [
|
|
24122
|
|
],
|
|
"shirt": 24118,
|
|
"pants": 24123,
|
|
"headColor": "#e0e0e0",
|
|
"torsoColor": "#e0e0e0",
|
|
"leftArmColor": "#e0e0e0",
|
|
"rightArmColor": "#e0e0e0",
|
|
"leftLegColor": "#e0e0e0",
|
|
"rightLegColor": "#e0e0e0"
|
|
}
|
|
UpdateAvatar()
|
|
});
|
|
|
|
let Myself = document.getElementById('myself')
|
|
Myself.addEventListener('click', function(){
|
|
LoadMyself()
|
|
});
|
|
|
|
let JSONUpload = document.getElementById('jsonUpload')
|
|
JSONUpload.addEventListener('change', function(){
|
|
let Reader = new FileReader()
|
|
Reader.addEventListener('loadend', function(){
|
|
Avatar = JSON.parse(Reader.result)
|
|
UpdateAvatar()
|
|
|
|
JSONUpload.value = ""
|
|
});
|
|
|
|
Reader.readAsText(JSONUpload.files[0])
|
|
});
|
|
|
|
let JSONSave = document.getElementById('jsonSave')
|
|
JSONSave.addEventListener('click', function(){
|
|
let Download = document.createElement('a')
|
|
Download.href = URL.createObjectURL(new Blob([JSON.stringify(Avatar)], {
|
|
type: "application/json"
|
|
}));
|
|
Download.setAttribute('download', 'AvatarSandbox.json')
|
|
document.body.appendChild(Download)
|
|
Download.click()
|
|
document.body.removeChild(Download)
|
|
});
|
|
|
|
let OpenInNewTab = document.getElementById('openNewTab')
|
|
OpenInNewTab.addEventListener('click', function(){
|
|
UpdateAvatar()
|
|
});
|
|
});
|
|
}
|
|
|
|
function UpdateAvatar() {
|
|
GenerateHash()
|
|
.then(hash => {
|
|
IFrame.addEventListener('load', function () {
|
|
IFrame.src = 'https://polytoria.com/ptstatic/itemview/#' + hash;
|
|
});
|
|
IFrame.src = 'about:blank';
|
|
});
|
|
}
|
|
|
|
function LoadFile(path, callback) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.onload = function () { return callback(this.responseText); }
|
|
xhr.open("GET", path, true);
|
|
xhr.send();
|
|
}
|
|
|
|
async function GenerateHash(data) {
|
|
if (!data) {
|
|
console.log('Data not provided')
|
|
let FormattedAvatar = await FormatAvatar()
|
|
return btoa(encodeURIComponent(JSON.stringify(FormattedAvatar)))
|
|
} else {
|
|
console.log('Data provided')
|
|
return btoa(encodeURIComponent(JSON.stringify(data)))
|
|
}
|
|
}
|
|
|
|
function RefreshItems() {
|
|
fetch(`https://api.polytoria.com/v1/store?search=${Search.value}&types%5B%5D=${TabSelected}&sort=createdAt&order=desc&page=${Page}&limit=12`)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
Array.from(ItemGrid.children).forEach(element => {element.remove()});
|
|
data = data.assets
|
|
data.forEach(item => {
|
|
let NewItemCard = document.createElement('div')
|
|
NewItemCard.setAttribute('data-id', item.id)
|
|
NewItemCard.classList = 'col-auto'
|
|
NewItemCard.innerHTML = `
|
|
<div style="max-width: 150px;">
|
|
<div class="card mb-2 avatar-item-container">
|
|
<div class="p-2">
|
|
<img src="${item.thumbnail}" class="img-fluid">
|
|
<span class="position-absolute" style="top: 5px; left: 5px; z-index: 1;">
|
|
<span class="badge bg-secondary">${item.type.charAt(0).toUpperCase() + item.type.substring(1)}</span>
|
|
</span>
|
|
<button class="avatarAction btn btn-success btn-sm position-absolute rounded-circle text-center" style="top: -10px; right: -16px; width: 32px; height: 32px; z-index: 1;"><i class="fas fa-plus"></i></button>
|
|
</div>
|
|
</div>
|
|
<a href="/store/${item.id}" class="text-reset">
|
|
<h6 class="text-truncate mb-0">${item.name}</h6>
|
|
</a>
|
|
<small class="text-muted d-block text-truncate">
|
|
by <a href="/users/${item.creator.id}" class="text-reset">${item.creator.name}</a>
|
|
</small>
|
|
</div>
|
|
`
|
|
NewItemCard.getElementsByClassName('p-2')[0].addEventListener('click', function(){
|
|
WearAsset(NewItemCard, item)
|
|
});
|
|
|
|
ItemGrid.appendChild(NewItemCard)
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error('Fetch error:', error);
|
|
});
|
|
}
|
|
|
|
async function FormatAvatar() {
|
|
const FormattedAvatar = structuredClone(Avatar)
|
|
|
|
// Hats, Tools: https://api.polytoria.com/v1/assets/serve-mesh/:id
|
|
// or: https://api.polytoria.com/v1/assets/serve/:id/Asset
|
|
|
|
Avatar.items.forEach(async (item, index) => {
|
|
if (typeof(item) === 'number') {
|
|
console.log(item)
|
|
await FetchMesh(item)
|
|
.then(URL => {
|
|
console.log('URL: ' + URL)
|
|
FormattedAvatar.items[index] = URL
|
|
})
|
|
.catch(error => {
|
|
throw new Error(error)
|
|
});
|
|
console.log('after url')
|
|
//Avatar.items[index] = URL
|
|
}
|
|
});
|
|
|
|
if (typeof(FormattedAvatar.tool) === 'number') {console.log(FormattedAvatar.tool); FormattedAvatar.tool = await FetchMesh(FormattedAvatar.tool)}
|
|
|
|
if (FormattedAvatar.face && typeof(FormattedAvatar.face) === 'number') {
|
|
FormattedAvatar.face = await FetchAsset(FormattedAvatar.face)
|
|
} else {
|
|
FormattedAvatar.face = "https://c0.ptacdn.com/static/3dview/DefaultFace.png"
|
|
}
|
|
|
|
if (typeof(FormattedAvatar.shirt) === 'number') {FormattedAvatar.shirt = await FetchAsset(FormattedAvatar.shirt)}
|
|
if (typeof(FormattedAvatar.pants) === 'number') {FormattedAvatar.pants = await FetchAsset(FormattedAvatar.pants)}
|
|
|
|
console.log('Real Avatar: ', Avatar, 'Formatted: ', FormattedAvatar)
|
|
return FormattedAvatar
|
|
}
|
|
|
|
function LoadMyself() {
|
|
fetch('https://api.polytoria.com/v1/users/:id/avatar'.replace(':id', UserID))
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network not ok')
|
|
}
|
|
return response.json()
|
|
})
|
|
.then(data => {
|
|
Avatar.items = []
|
|
|
|
data.assets.forEach(item => {
|
|
switch(item.type) {
|
|
case 'hat':
|
|
Avatar.items.push(item.id)
|
|
break
|
|
default:
|
|
Avatar[item.type] = item.id
|
|
break
|
|
}
|
|
});
|
|
|
|
Avatar.headColor = '#' + data.colors.head || '#cdcdcd'
|
|
Avatar.torsoColor = '#' + data.colors.torso || '#cdcdcd'
|
|
Avatar.leftArmColor = '#' + data.colors.leftArm || '#cdcdcd'
|
|
Avatar.rightArmColor = '#' + data.colors.rightArm || '#cdcdcd'
|
|
Avatar.leftLegColor = '#' + data.colors.leftLeg || '#cdcdcd'
|
|
Avatar.rightLegColor = '#' + data.colors.rightLeg || '#cdcdcd'
|
|
|
|
UpdateAvatar()
|
|
})
|
|
.catch(error => {
|
|
console.log(error)
|
|
});
|
|
}
|
|
|
|
function WearAsset(element, info) {
|
|
if (Avatar.items.indexOf(info.id) === -1 && Avatar[info.type] !== info.id) {
|
|
console.log('Equip', info)
|
|
switch(info.type) {
|
|
case 'hat':
|
|
Avatar.items.push(info.id)
|
|
break
|
|
default:
|
|
Avatar[info.type] = info.id
|
|
break
|
|
}
|
|
} else {
|
|
console.log('unequip', info)
|
|
switch(info.type) {
|
|
case 'hat':
|
|
Avatar.items.splice(Avatar.items.indexOf(info.id), 1)
|
|
break
|
|
case 'face':
|
|
Avatar.face = "https://c0.ptacdn.com/static/3dview/DefaultFace.png"
|
|
break
|
|
default:
|
|
Avatar[info.type] = undefined
|
|
break
|
|
}
|
|
}
|
|
|
|
const ToggleButton = element.getElementsByClassName('avatarAction')[0]
|
|
ToggleButton.classList.toggle('btn-success')
|
|
ToggleButton.classList.toggle('btn-danger')
|
|
ToggleButton.children[0].classList.toggle('fa-plus')
|
|
ToggleButton.children[0].classList.toggle('fa-minus')
|
|
|
|
const Duplicate = ItemGrid.querySelector(`[data-id="${info.id}"]`)
|
|
if (Duplicate !== null && Duplicate !== element) {
|
|
const DuplicateToggleButton = Duplicate.getElementsByClassName('avatarAction')[0]
|
|
DuplicateToggleButton.classList.toggle('btn-success')
|
|
DuplicateToggleButton.classList.toggle('btn-danger')
|
|
DuplicateToggleButton.children[0].classList.toggle('fa-plus')
|
|
DuplicateToggleButton.children[0].classList.toggle('fa-minus')
|
|
}
|
|
|
|
LoadWearing()
|
|
UpdateAvatar()
|
|
}
|
|
|
|
async function FetchMesh(id) {
|
|
if (id === null) {return null}
|
|
console.log('https://api.polytoria.com/v1/assets/serve-mesh/:id'.replace(':id', id))
|
|
return fetch('https://api.polytoria.com/v1/assets/serve-mesh/:id'.replace(':id', id))
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network not ok')
|
|
}
|
|
return response.json()
|
|
})
|
|
.then(data => {
|
|
console.log(data, 'finished', data.url)
|
|
return data.url
|
|
})
|
|
.catch(error => {
|
|
console.log('Fetch error: ' + error)
|
|
});
|
|
}
|
|
|
|
async function FetchAsset(id) {
|
|
if (id === null) {return null}
|
|
return fetch('https://api.polytoria.com/v1/assets/serve/:id/Asset'.replace(':id', id))
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network not ok')
|
|
}
|
|
return response.json()
|
|
})
|
|
.then(data => {
|
|
return data.url
|
|
})
|
|
.catch(error => {
|
|
console.log('Fetch error: ' + error)
|
|
});
|
|
}
|
|
|
|
function LoadWearing() {
|
|
const WearingItems = [
|
|
...Avatar.items,
|
|
Avatar.shirt,
|
|
Avatar.pants,
|
|
Avatar.face
|
|
].filter(item => item !== null && item !== undefined);
|
|
|
|
Array.from(Wearing.children).forEach(element => {
|
|
const ItemID = element.getElementsByTagName('a')[0].href.split('/')[2]
|
|
if (!WearingItems.includes(ItemID)) {
|
|
element.remove();
|
|
}
|
|
});
|
|
|
|
WearingItems.forEach(item => {
|
|
const ExistingElement = Wearing.querySelector(`[data-itemid="${item}"]`);
|
|
|
|
if (!ExistingElement) {
|
|
fetch(`https://api.polytoria.com/v1/store/${item}`)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(item => {
|
|
if (Wearing.innerHTML === 'No items to show.') {
|
|
Wearing.innerHTML = ''
|
|
}
|
|
let NewItemCard = document.createElement('div');
|
|
NewItemCard.setAttribute('data-id', item.id)
|
|
NewItemCard.classList = 'col-auto';
|
|
NewItemCard.innerHTML = `
|
|
<div style="max-width: 150px;">
|
|
<div class="card mb-2 avatar-item-container">
|
|
<div class="p-2">
|
|
<img src="${item.thumbnail}" class="img-fluid">
|
|
<span class="position-absolute" style="top: 5px; left: 5px; z-index: 1;">
|
|
<span class="badge bg-secondary">${item.type.charAt(0).toUpperCase() + item.type.substring(1)}</span>
|
|
</span>
|
|
<button class="avatarAction btn btn-danger btn-sm position-absolute rounded-circle text-center" style="top: -10px; right: -16px; width: 32px; height: 32px; z-index: 1;"><i class="fas fa-minus"></i></button>
|
|
</div>
|
|
</div>
|
|
<a href="/store/${item.id}" class="text-reset">
|
|
<h6 class="text-truncate mb-0">${item.name}</h6>
|
|
</a>
|
|
<small class="text-muted d-block text-truncate">
|
|
by <a href="/users/${item.creator.id}" class="text-reset">${item.creator.name}</a>
|
|
</small>
|
|
</div>
|
|
`
|
|
Wearing.appendChild(NewItemCard);
|
|
NewItemCard.getElementsByClassName('p-2')[0].addEventListener('click', function () {
|
|
WearAsset(NewItemCard, item);
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.log('Fetch error: ' + error);
|
|
});
|
|
}
|
|
});
|
|
|
|
if (Array.from(Wearing.children).length === 0) {
|
|
Wearing.innerHTML = 'No items to show.'
|
|
}
|
|
} |