263 lines
11 KiB
JavaScript
263 lines
11 KiB
JavaScript
(() => {
|
|
const
|
|
_Profile = $('.profile-wrapper'),
|
|
_Preview = $('.profile-container'),
|
|
_Status = $('#profile-status'),
|
|
// Option Elements
|
|
iDisplayname = $('#input-displayname'),
|
|
iSubtitle = $('#input-subtitle'),
|
|
iBio = $('#input-bio'),
|
|
iAvatarFile = $('#input-avatar-file'),
|
|
iBannerFile = $('#input-banner-file'),
|
|
iBannerColor = $('#input-banner'),
|
|
iBorderColor = $('#input-border'),
|
|
iBackgroundColor = $('#input-background'),
|
|
iSubmit = $('#button-submit'),
|
|
iCancel = $('#button-cancel'),
|
|
// Preview Elements
|
|
pBanner = $('#profile-banner'),
|
|
pAvatar = $('#profile-avatar'),
|
|
pBadges = $('#profile-badges'),
|
|
pDisplayname = $('#profile-displayname'),
|
|
pUsername = $('#profile-username'),
|
|
pSubtitle = $('#profile-subtitle'),
|
|
pDivider = $('#profile-divider'),
|
|
pBio = $('#profile-bio'),
|
|
// Buttons
|
|
bAvatar = $('#button-avatar-remove'),
|
|
bBanner = $('#button-banner-remove')
|
|
|
|
// Elements that the user interacts with in real time
|
|
const _InputElements = [
|
|
iDisplayname,
|
|
iSubtitle,
|
|
iBio,
|
|
iBannerColor,
|
|
iBorderColor,
|
|
iBackgroundColor,
|
|
// These elements have async calls
|
|
// they'll update the preview when complete
|
|
// pBanner,
|
|
// pAvatar,
|
|
]
|
|
const _RecognizedBadges = [
|
|
[1 << 0, 'crown', 'The Boss'],
|
|
[1 << 1, 'star', 'V.I.P'],
|
|
[1 << 2, 'picross', 'Picross Master'],
|
|
]
|
|
|
|
SendRequest('GET', '/api/v1/users/@me', null, 1)
|
|
.then(([_, body]) => {
|
|
let removingBanner = false
|
|
let removingAvatar = false
|
|
let unsavedChanges = false
|
|
const hexToDec = e => parseInt(e.value.slice(1), 16)
|
|
const trimDataURL = (s, x = undefined) => s.slice(s.indexOf(',') + 1, x)
|
|
const decToHex = (e, x) => '#' + (e?.toString(16).padStart('6', 0) || x)
|
|
|
|
function FormReset() {
|
|
const colorBanner = decToHex(body.accent_banner, '1d1e2e')
|
|
const colorBorder = decToHex(body.accent_border, '282a3f')
|
|
const colorBackground = decToHex(body.accent_background, '333550')
|
|
|
|
// Reset Options
|
|
iDisplayname.value = body.displayname
|
|
iSubtitle.value = body.subtitle
|
|
iBio.value = body.biography
|
|
iBannerColor.value = colorBanner
|
|
iBorderColor.value = colorBorder
|
|
iBackgroundColor.value = colorBackground
|
|
iAvatarFile.value = null
|
|
iBannerFile.value = null
|
|
|
|
// Reset Preview
|
|
pDisplayname.textContent = body.displayname
|
|
pUsername.textContent = '@' + body.username
|
|
pSubtitle.textContent = body.subtitle
|
|
pBio.textContent = body.biography
|
|
body.biography
|
|
? pDivider.removeAttribute('hidden')
|
|
: pDivider.setAttribute('hidden', true)
|
|
pAvatar.src = ImageURL('avatars', body.id, body.avatar, true, 128)
|
|
pBanner.style.backgroundImage = body.banner
|
|
? `url('${ImageURL('banners', body.id, body.banner, true, 512)}')`
|
|
: ''
|
|
_Profile.style.setProperty('--accent-banner', colorBanner)
|
|
_Profile.style.setProperty('--accent-border', colorBorder)
|
|
_Profile.style.setProperty('--accent-background', colorBackground)
|
|
iBackgroundColor.oninput()
|
|
|
|
// Disable Buttons
|
|
removingAvatar = false
|
|
removingBanner = false
|
|
FormUpdated()
|
|
}
|
|
function FormUpdated() {
|
|
unsavedChanges = (Object.entries(CollectBody()).length > 0)
|
|
if (unsavedChanges) {
|
|
iCancel.removeAttribute('disabled')
|
|
iSubmit.removeAttribute('disabled')
|
|
} else {
|
|
iCancel.setAttribute('disabled', true)
|
|
iSubmit.setAttribute('disabled', true)
|
|
}
|
|
!removingBanner && (body.banner !== null || iBannerFile.files.length > 0)
|
|
? bBanner.removeAttribute('disabled')
|
|
: bBanner.setAttribute('disabled', true)
|
|
|
|
!removingAvatar && (body.avatar !== null || iAvatarFile.files.length > 0)
|
|
? bAvatar.removeAttribute('disabled')
|
|
: bAvatar.setAttribute('disabled', true)
|
|
}
|
|
function CollectBody() {
|
|
const data = {}
|
|
// Collect Textboxes
|
|
if ((iDisplayname.value.trim() || body.displayname) !== body.displayname)
|
|
data['displayname'] = iDisplayname.value
|
|
if (iBio.value.trim() !== (body.biography || ''))
|
|
data['biography'] = iBio.value
|
|
if (iSubtitle.value.trim() !== (body.subtitle || ''))
|
|
data['subtitle'] = iSubtitle.value
|
|
|
|
// Collect Colors
|
|
const decBannerColor = hexToDec(iBannerColor)
|
|
if (decBannerColor !== (body.accent_banner || 1908270))
|
|
data['accent_banner'] = decBannerColor
|
|
const decBorderColor = hexToDec(iBorderColor)
|
|
if (decBorderColor !== (body.accent_border || 2632255))
|
|
data['accent_border'] = decBorderColor
|
|
const decBackgroundColor = hexToDec(iBackgroundColor)
|
|
if (decBackgroundColor !== (body.accent_background || 3355984))
|
|
data['accent_background'] = decBackgroundColor
|
|
|
|
// Collect Images
|
|
if (removingAvatar && body.avatar) data['avatar'] = ''
|
|
if (removingBanner && body.banner) data['banner'] = ''
|
|
if (iAvatarFile.files.length)
|
|
data['avatar'] = trimDataURL(pAvatar.src)
|
|
if (iBannerFile.files.length)
|
|
data['banner'] = trimDataURL(pBanner.style.backgroundImage, -2)
|
|
|
|
console.log(data)
|
|
return data
|
|
}
|
|
|
|
// Templating
|
|
_InputElements.forEach(e => e.addEventListener('change', FormUpdated))
|
|
_RecognizedBadges.forEach(b => {
|
|
if ((body.public_flags & b[0]) !== 0) {
|
|
const img = document.createElement('img')
|
|
img.src = `/assets/images/icons/badge-${b[1]}.svg`
|
|
img.title = b[2]
|
|
img.alt = b[2]
|
|
pBadges.appendChild(img)
|
|
}
|
|
})
|
|
|
|
// Section: About Me
|
|
iDisplayname.oninput = () => pDisplayname.textContent = (iDisplayname.value || body.displayname).trim()
|
|
iSubtitle.oninput = () => pSubtitle.textContent = iSubtitle.value.trim()
|
|
iBio.oninput = () => {
|
|
const content = (iBio.value || '')
|
|
pBio.textContent = content.trim()
|
|
content.length > 0
|
|
? pDivider.removeAttribute('hidden')
|
|
: pDivider.setAttribute('hidden', true)
|
|
}
|
|
|
|
// Section: Images
|
|
$('#button-avatar').onclick = () => iAvatarFile.click()
|
|
$('#button-banner').onclick = () => iBannerFile.click()
|
|
bAvatar.onclick = () => {
|
|
pAvatar.src = ImageURL('avatars', body.id, null)
|
|
iAvatarFile.value = null
|
|
removingAvatar = true
|
|
FormUpdated()
|
|
}
|
|
bBanner.onclick = () => {
|
|
pBanner.style.backgroundImage = null
|
|
iBannerFile.value = null
|
|
removingBanner = true
|
|
FormUpdated()
|
|
}
|
|
|
|
iAvatarFile.onchange = (ev) => {
|
|
const file = ev.target.files[0]
|
|
if (!file) return
|
|
const reader = new FileReader()
|
|
reader.onload = e => {
|
|
pAvatar.src = e.target.result
|
|
removingAvatar = false
|
|
FormUpdated()
|
|
}
|
|
reader.readAsDataURL(file)
|
|
}
|
|
iBannerFile.onchange = (ev) => {
|
|
const file = ev.target.files[0]
|
|
if (!file) return
|
|
const reader = new FileReader()
|
|
reader.onload = e => {
|
|
pBanner.style.backgroundImage = `url(${e.target.result})`
|
|
removingBanner = false
|
|
FormUpdated()
|
|
}
|
|
reader.readAsDataURL(file)
|
|
}
|
|
|
|
// Section: Accents
|
|
iBannerColor.oninput = () => _Profile.style.setProperty('--accent-banner', iBannerColor.value)
|
|
iBorderColor.oninput = () => _Profile.style.setProperty('--accent-border', iBorderColor.value)
|
|
iBackgroundColor.oninput = () => {
|
|
let hexColor = iBackgroundColor.value
|
|
_Profile.style.setProperty('--accent-background', hexColor)
|
|
|
|
// Check Luminance of Background Color
|
|
hexColor = hexColor.replace('#', '')
|
|
var r = parseInt(hexColor.substr(0, 2), 16)
|
|
var g = parseInt(hexColor.substr(2, 2), 16)
|
|
var b = parseInt(hexColor.substr(4, 2), 16)
|
|
if (((0.299 * r) + (0.587 * g) + (0.114 * b)) / 255 > 0.85) {
|
|
_Preview.classList.add('profile-dark')
|
|
} else {
|
|
_Preview.classList.remove('profile-dark')
|
|
}
|
|
}
|
|
|
|
// Section: Actions
|
|
iCancel.onclick = () => FormReset()
|
|
iSubmit.onclick = () => {
|
|
if (!unsavedChanges) return
|
|
const unlock = LockInteraction()
|
|
_Status.textContent = 'Saving Changes...'
|
|
SendRequest('PATCH', '/api/v1/users/@me', CollectBody(), 1)
|
|
.then(([_, patchedBody]) => {
|
|
_Status.textContent = 'Profile Saved!'
|
|
_Status.classList.remove('text-error')
|
|
localStorage.removeItem('cache_home_me') // Used by page-home.js
|
|
body = patchedBody
|
|
unlock()
|
|
FormReset()
|
|
})
|
|
.catch(e => {
|
|
_Status.textContent = e
|
|
_Status.classList.add('text-error')
|
|
unlock()
|
|
})
|
|
// we dont use finally block here because race condition :p
|
|
}
|
|
|
|
// Display Profile
|
|
_Profile.removeAttribute('hidden')
|
|
FormReset()
|
|
})
|
|
.catch(e => {
|
|
// Display Error Message
|
|
$('#alert-error').removeAttribute('hidden')
|
|
$('#error-message').textContent = e
|
|
console.log(e)
|
|
})
|
|
.finally(() => {
|
|
// Hide Loading Symbol
|
|
$('#alert-load').setAttribute('hidden', true)
|
|
})
|
|
})() |