f0ckv2/public/s/js/admin.js

384 lines
12 KiB
JavaScript
Raw Normal View History

2021-05-25 12:44:35 +00:00
let flashActive = false;
const flashTypes = [ "error", "success", "warn" ];
const flash = ({ type, msg }) => {
let flashContainer;
if(tmp = document.querySelector("div#flash"))
flashContainer = tmp;
else {
flashContainer = document.createElement("div");
flashContainer.id = "flash";
document.body.insertAdjacentElement("afterbegin", flashContainer);
}
flashContainer.innerHTML = msg;
if(flashTypes.includes(type)) {
flashContainer.className = "";
flashContainer.classList.add(type);
}
if(flashActive)
return false;
flashActive = true;
flashContainer.animate(
[ { bottom: "-28px" }, { bottom: 0 } ], {
2021-12-04 10:08:55 +00:00
duration: 500,
2021-05-25 12:44:35 +00:00
fill: "both"
}
).onfinish = () => setTimeout(() => {
flashContainer.animate(
[ { bottom: 0 }, { bottom: "-28px" } ], {
2021-12-04 10:08:55 +00:00
duration: 500,
2021-05-25 12:44:35 +00:00
fill: "both"
}
).onfinish = () => flashActive = false;
}, 4 * 1e3);
return true;
};
(async () => {
if(_addtag = document.querySelector("a#a_addtag")) {
const postid = +document.querySelector("a.id-link").innerText;
2021-12-06 09:21:11 +00:00
const poster = document.querySelector("a#a_username").innerText;
2021-05-25 12:44:35 +00:00
let tags = [...document.querySelectorAll("#tags > .badge")].map(t => t.innerText.slice(0, -2));
const deleteEvent = async e => {
e.preventDefault();
if(!confirm("Do you really want to delete this tag?"))
return;
2022-03-24 19:29:20 +00:00
const tagname = e.target.parentElement.querySelector('a:first-child').innerText;
2022-03-25 14:24:12 +00:00
const res = await (await fetch("/api/v2/admin/" + postid + "/tags/" + encodeURIComponent(tagname), {
method: 'DELETE'
})).json();
2021-05-25 12:44:35 +00:00
if(!res.success)
return alert("uff");
tags = res.tags.map(t => t.tag);
renderTags(res.tags);
};
2022-03-24 15:13:51 +00:00
const queryapi = async (url, data, method = 'GET') => {
let req;
if(method == 'POST') {
req = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
}
else {
let s = [];
for(const [ key, val ] of Object.entries(data))
s.push(encodeURIComponent(key) + "=" + encodeURIComponent(val));
req = await fetch(url + '?' + s.join('&'));
}
return await req.json();
2022-03-24 14:35:40 +00:00
};
2022-03-24 15:13:51 +00:00
const get = async (url, data) => queryapi(url, data, 'GET');
const post = async (url, data) => queryapi(url, data, 'POST');
2021-05-25 12:44:35 +00:00
const renderTags = _tags => {
[...document.querySelectorAll("#tags > .badge")].forEach(tag => tag.parentElement.removeChild(tag));
_tags.reverse().forEach(tag => {
const a = document.createElement("a");
2021-12-23 05:07:08 +00:00
a.href = `/tag/${tag.tag}`;
2021-05-25 12:44:35 +00:00
a.style = "color: inherit !important";
2021-12-25 12:12:53 +00:00
a.innerHTML = tag.tag;
2022-03-27 16:34:13 +00:00
a.addEventListener("click", editTagEvent); // tmp
2021-05-25 12:44:35 +00:00
const span = document.createElement("span");
2021-12-29 04:48:04 +00:00
span.classList.add("badge", "mr-2");
2021-12-26 22:11:16 +00:00
span.setAttribute('tooltip', tag.user);
2021-12-25 12:12:53 +00:00
2021-12-29 04:48:04 +00:00
tag.badge.split(" ").forEach(b => span.classList.add(b));
2021-05-25 12:44:35 +00:00
const delbutton = document.createElement("a");
delbutton.innerHTML = " ×";
delbutton.href = "#";
delbutton.addEventListener("click", deleteEvent);
span.insertAdjacentElement("beforeend", a);
span.insertAdjacentElement("beforeend", delbutton);
document.querySelector("#tags").insertAdjacentElement("afterbegin", span);
});
};
const addtagClick = (ae = false) => {
if(ae)
ae.preventDefault();
const insert = document.querySelector("a#a_addtag");
const span = document.createElement("span");
span.classList.add("badge", "badge-light", "mr-2");
const input = document.createElement("input");
input.size = "10";
input.value = "";
2022-03-24 04:13:10 +00:00
input.setAttribute("list", "testlist");
2022-03-24 11:29:59 +00:00
input.setAttribute("autoComplete", "off");
2021-05-25 12:44:35 +00:00
2022-03-24 04:13:10 +00:00
span.insertAdjacentElement("afterbegin", input);
insert.insertAdjacentElement("beforebegin", span);
input.focus();
let tt = null;
let lastInput = '';
2022-03-24 14:35:40 +00:00
const testList = document.querySelector('#testlist');
2022-03-24 04:13:10 +00:00
input.addEventListener("keyup", async e => {
2021-05-25 12:44:35 +00:00
if(e.key === "Enter") {
2021-12-30 02:38:39 +00:00
const tmptag = input.value?.trim();
2021-05-25 12:44:35 +00:00
if(tags.includes(tmptag))
return alert("tag already exists");
2022-03-25 14:24:12 +00:00
const res = await post("/api/v2/admin/" + postid + "/tags", {
tagname: tmptag
});
2021-05-25 12:44:35 +00:00
if(!res.success) {
return flash({
type: "error",
msg: res.msg
});
}
tags = res.tags.map(t => t.tag);
renderTags(res.tags);
addtagClick();
2022-03-24 04:13:10 +00:00
testList.innerText = "";
2021-05-25 12:44:35 +00:00
}
else if(e.key === "Escape") {
span.parentElement.removeChild(span);
2022-03-24 04:13:10 +00:00
testList.innerText = "";
2021-05-25 12:44:35 +00:00
}
2022-03-24 04:13:10 +00:00
else {
if(tt != null)
clearTimeout(tt);
2021-05-25 12:44:35 +00:00
2022-03-24 04:13:10 +00:00
tt = setTimeout(async () => {
2022-03-25 14:24:12 +00:00
tt = null;
2021-05-25 12:44:35 +00:00
2022-03-24 04:13:10 +00:00
const tmptag = input.value?.trim();
if(tmptag == lastInput || tmptag.length <= 1)
return false;
testList.innerText = "";
lastInput = tmptag;
2022-03-24 14:35:40 +00:00
const res = await get('/api/v2/admin/tags/suggest', {
q: tmptag
});
2022-03-24 04:13:10 +00:00
for(const entry of res.suggestions) {
const option = document.createElement('option');
option.value = entry.tag;
2022-03-24 11:29:59 +00:00
if(!/fox/.test(navigator.userAgent))
2022-03-29 12:33:43 +00:00
option.innerText = `tagged ${entry.tagged} times (score: ${entry.score.toFixed(2)})`;
2022-03-24 11:29:59 +00:00
2022-03-24 04:13:10 +00:00
testList.insertAdjacentElement('beforeEnd', option);
};
}, 500);
}
return true;
});
2021-05-25 12:44:35 +00:00
input.addEventListener("focusout", ie => {
if(input.value.length === 0)
input.parentElement.parentElement.removeChild(input.parentElement);
});
};
const toggleEvent = async (e = false) => {
if(e)
e.preventDefault();
2022-03-25 14:24:12 +00:00
const res = await (await fetch('/api/v2/admin/' + encodeURIComponent(postid) + '/tags/toggle', {
method: 'PUT'
})).json();
2021-05-25 12:44:35 +00:00
renderTags(res.tags);
tags = res.tags.map(t => t.tag);
flash({
type: "success",
msg: tags.join()
});
};
const deleteButtonEvent = async e => {
if(e)
e.preventDefault();
if(!confirm(`Reason for deleting f0ckpost ${postid} by ${poster} (Weihnachten™)`))
return;
2022-03-25 14:24:12 +00:00
const res = await post("/api/v2/admin/deletepost", {
postid: postid
});
2021-05-25 12:44:35 +00:00
if(res.success) {
flash({
type: "success",
msg: "post was successfully deleted"
});
}
else {
flash({
type: "error",
msg: res.msg
});
}
};
2022-01-01 01:17:31 +00:00
const toggleFavEvent = async e => {
2022-03-24 15:13:51 +00:00
const res = await post('/api/v2/admin/togglefav', {
2022-03-24 14:35:40 +00:00
postid: postid
});
2022-01-01 01:17:31 +00:00
if(res.success) {
const fav = document.querySelector("svg#a_favo > use").href;
fav.baseVal = '/s/img/iconset.svg#heart_' + (fav.baseVal.match(/heart_(regular|solid)$/)[1] == "solid" ? "regular" : "solid");
// span#favs
const favcontainer = document.querySelector('span#favs');
2022-01-02 05:52:52 +00:00
favcontainer.innerHTML = "";
2022-01-03 04:14:19 +00:00
favcontainer.hidden = !(favcontainer.hidden || res.favs.length > 0);
2022-01-02 05:52:52 +00:00
res.favs.forEach(f => {
const a = document.createElement('a');
a.href = `/user/${f.user}/favs`;
a.setAttribute('tooltip', f.user);
2022-05-06 08:56:45 +00:00
a.setAttribute('flow', 'up');
2022-01-02 05:52:52 +00:00
const img = document.createElement('img');
2022-01-05 19:21:50 +00:00
img.src = `/t/${f.avatar}.webp`;
2022-01-02 05:52:52 +00:00
img.style.height = "32px";
img.style.width = "32px";
a.insertAdjacentElement('beforeend', img);
favcontainer.insertAdjacentElement('beforeend', a);
favcontainer.innerHTML += "&nbsp;";
});
2022-01-01 01:17:31 +00:00
}
else {
// lul
}
};
2022-03-27 16:34:13 +00:00
let tmptt = null;
const editTagEvent = async e => { // mousedown
e.preventDefault();
if(e.detail === 2) {
clearTimeout(tmptt);
const old = e.target;
const parent = e.target.parentElement;
const oldtag = e.target.innerText;
const textfield = document.createElement('input');
textfield.value = e.target.innerText;
textfield.size = 10;
parent.insertAdjacentElement('afterbegin', textfield);
textfield.focus();
parent.removeChild(e.target);
parent.querySelector('a:last-child').style.display = 'none';
textfield.addEventListener("keyup", async e => {
if(e.key === 'Enter') {
// send
let res = await fetch('/api/v2/admin/tags/' + encodeURIComponent(oldtag), {
method: 'PUT',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
newtag: textfield.value
})
});
const status = res.status;
res = await res.json();
switch(status) {
case 200: // success, change
case 201:
parent.removeChild(textfield);
parent.insertAdjacentElement('afterbegin', old);
parent.querySelector('a:last-child').style.display = '';
old.href = `/tag/${res.tag}`;
old.innerText = res.tag.trim();
break;
default:
console.log(res);
break;
}
}
else if(e.key === 'Escape') {
parent.removeChild(textfield);
parent.insertAdjacentElement('afterbegin', old);
parent.querySelector('a:last-child').style.display = '';
}
});
}
else
tmptt = setTimeout(() => location.href = e.target.href, 250);
return false;
};
2021-05-25 12:44:35 +00:00
_addtag.addEventListener("click", addtagClick);
document.querySelector("a#a_toggle").addEventListener("click", toggleEvent);
2022-03-27 16:34:13 +00:00
[...document.querySelectorAll("#tags > .badge > a:first-child")].map(t => t.addEventListener("click", editTagEvent));
2021-05-25 12:44:35 +00:00
[...document.querySelectorAll("#tags > .badge > a:last-child")].map(t => t.addEventListener("click", deleteEvent));
2022-01-01 01:17:31 +00:00
document.querySelector("svg#a_delete").addEventListener("click", deleteButtonEvent);
document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent);
2021-05-25 12:44:35 +00:00
document.addEventListener("keyup", e => {
if(e.target.tagName === "INPUT")
return;
if(e.key === "p")
toggleEvent();
else if(e.key === "i")
addtagClick();
else if(e.key === "x")
deleteButtonEvent();
2022-01-03 04:14:19 +00:00
else if(e.key === "f")
toggleFavEvent();
2021-05-25 12:44:35 +00:00
});
}
2022-03-28 15:32:00 +00:00
if(document.location.pathname === '/settings') {
const saveAvatar = async e => {
e.preventDefault();
2022-03-29 12:33:43 +00:00
2022-03-28 15:32:00 +00:00
const avatar = +document.querySelector('input[name="i_avatar"]').value;
let res = await fetch('/api/v2/settings/setAvatar', {
method: 'PUT',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ avatar })
});
const code = res.status;
res = await res.json();
switch(code) {
case 200:
document.querySelector('#img_avatar').src = `/t/${avatar}.webp`;
document.querySelector('img.avatar').src = `/t/${avatar}.webp`;
break;
default:
console.log(res);
break;
}
};
document.querySelector('input#s_avatar').addEventListener('click', saveAvatar);
document.querySelector('input[name="i_avatar"]').addEventListener('keyup', async e => {
if(e.key === 'Enter')
await saveAvatar(e);
});
}
2021-05-25 12:44:35 +00:00
})();