169 lines
5.8 KiB
JavaScript
169 lines
5.8 KiB
JavaScript
(function(){
|
|
"use strict";
|
|
|
|
|
|
|
|
function attachUsernameInput(){
|
|
const usernameInputs = document.getElementsByClassName('username-input');
|
|
for(var i=0;i<usernameInputs.length;i++)(function(usernameInput){
|
|
let lastValue = '';
|
|
const endpoint = usernameInput.getAttribute('data-endpoint');
|
|
let usernameInputMessage = document.createElement('small');
|
|
usernameInput.oninput = function(event){
|
|
let value = usernameInput.value;
|
|
if (value != lastValue){
|
|
if(!/^[a-z0-9_ ]*$/i.test(value)){
|
|
usernameInputMessage.innerHTML = 'Usernames can only contain letters, numbers, and underscores.';
|
|
usernameInputMessage.className = 'username-input-message error';
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
if(/ /.test(value)){
|
|
value = value.replace(/ /g,'_');
|
|
}
|
|
usernameInput.value = lastValue = value.toLowerCase();
|
|
if(!value){
|
|
usernameInputMessage.innerHTML = 'You cannot have an empty username.';
|
|
usernameInputMessage.className = 'username-input-message error';
|
|
return;
|
|
}
|
|
if(/^[01]/.test(value)) {
|
|
usernameInputMessage.innerHTML = 'Your username cannot start with 0 or 1.';
|
|
usernameInputMessage.className = 'username-input-message error';
|
|
return;
|
|
}
|
|
usernameInputMessage.innerHTML = 'Checking username...';
|
|
usernameInputMessage.className = 'username-input-message checking';
|
|
requestUsernameAvailability(value, endpoint).then((resp) => {
|
|
if (['ok', void 0].indexOf(resp.status) < 0){
|
|
usernameInputMessage.innerHTML = 'Sorry, there was an unknown error.';
|
|
usernameInputMessage.className = 'username-input-message error';
|
|
return;
|
|
}
|
|
if (resp.is_available){
|
|
usernameInputMessage.innerHTML = "The username @" + value + " is available!";
|
|
usernameInputMessage.className = 'username-input-message success';
|
|
return;
|
|
} else {
|
|
usernameInputMessage.innerHTML = "Sorry, someone else has this username already :(";
|
|
usernameInputMessage.className = 'username-input-message error';
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
usernameInputMessage.className = 'username-input-message';
|
|
usernameInput.parentNode.appendChild(usernameInputMessage);
|
|
})(usernameInputs[i]);
|
|
}
|
|
|
|
async function requestUsernameAvailability(u, endpoint){
|
|
return fetch(endpoint.replace('$1', encodeURIComponent(u))
|
|
).then((e) => e.json());
|
|
}
|
|
|
|
function enablePostVotes(){
|
|
for (let elem of document.querySelectorAll('.upvote-button')){
|
|
(function(e){
|
|
let p;
|
|
for (p = e; p && p != document.body && !p.hasAttribute('data-endpoint'); p = p.parentElement);
|
|
|
|
if (!p) return;
|
|
|
|
let endpoint = p.getAttribute('data-endpoint');
|
|
|
|
|
|
if (!endpoint || !/^[a-z0-9_]+$/.test(endpoint)) {
|
|
console.warn('missing endpoint!');
|
|
return;
|
|
}
|
|
|
|
|
|
let buttonUp = e.querySelector('.upvote-button-up'), buttonDown = e.querySelector('.upvote-button-down'),
|
|
upvoteCount = e.querySelector('.upvote-count');
|
|
let currentScore = buttonUp.classList.contains('active')? 1 : buttonDown.classList.contains('active')? -1 : 0;
|
|
|
|
buttonUp.addEventListener('click', function(){
|
|
sendVote(endpoint, (currentScore === 1? 0 : 1)).then((e) => {
|
|
buttonDown.classList.remove('active');
|
|
buttonDown.querySelector('i').className = 'icon icon-downvote';
|
|
if(currentScore === 1) {
|
|
buttonUp.classList.remove('active');
|
|
buttonUp.querySelector('i').className = 'icon icon-upvote';
|
|
} else {
|
|
buttonUp.classList.add('active');
|
|
buttonUp.querySelector('i').className = 'icon icon-upvote_fill';
|
|
}
|
|
upvoteCount.textContent = e.count !== void 0? e.count : upvoteCount.textContent;
|
|
currentScore = currentScore === 1? 0 : 1;
|
|
});
|
|
});
|
|
|
|
buttonDown.addEventListener('click', function(){
|
|
sendVote(endpoint, (currentScore === -1? 0 : -1)).then((e) => {
|
|
buttonUp.classList.remove('active');
|
|
buttonUp.querySelector('i').className = 'icon icon-upvote';
|
|
if(currentScore === -1) {
|
|
buttonDown.classList.remove('active');
|
|
buttonDown.querySelector('i').className = 'icon icon-downvote';
|
|
} else {
|
|
buttonDown.classList.add('active');
|
|
buttonDown.querySelector('i').className = 'icon icon-downvote_fill';
|
|
}
|
|
upvoteCount.textContent = e.count !== void 0? e.count : upvoteCount.textContent;
|
|
currentScore = currentScore === -1? 0 : -1;
|
|
});
|
|
});
|
|
})(elem);
|
|
}
|
|
}
|
|
|
|
function getCsrfToken(){
|
|
return document.querySelector('meta[name="csrf_token"]').content;
|
|
}
|
|
|
|
async function sendVote(endpoint, score){
|
|
return fetch(`/comments/${endpoint}/upvote`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
},
|
|
body: 'o=' + encodeURIComponent(score) + '&csrf_token=' + encodeURIComponent(getCsrfToken())
|
|
}).then(e => e.json());
|
|
}
|
|
|
|
function enableThemeChange() {
|
|
let schemeItems = document.querySelectorAll('.apply-theme [name="color_scheme"]');
|
|
|
|
for (let ii of schemeItems) {
|
|
ii.addEventListener('change', function(e) {
|
|
let removed_classes = Array.from(document.body.classList).filter((x) => /^color-scheme-/.test(x));
|
|
document.body.classList.remove(...removed_classes);
|
|
if (e.target.value !== 'unset') {
|
|
document.body.classList.add(`color-scheme-${e.target.value}`);
|
|
}
|
|
console.log(`Color scheme changed to ${e.target.value}`)
|
|
})
|
|
}
|
|
|
|
let themeItems = document.querySelectorAll('.apply-theme [name="color_theme"]');
|
|
|
|
for (let ii of themeItems) {
|
|
ii.addEventListener('change', function(e) {
|
|
let removed_classes = Array.from(document.body.classList).filter((x) => /^color-theme-/.test(x));
|
|
document.body.classList.remove(...removed_classes);
|
|
document.body.classList.add(`color-theme-${e.target.value}`);
|
|
console.log(`Color theme changed to ${e.target.value}`)
|
|
})
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
attachUsernameInput();
|
|
enablePostVotes();
|
|
enableThemeChange();
|
|
}
|
|
|
|
main();
|
|
|
|
})();
|