diff --git a/public/s/js/admin.js b/public/s/js/admin.js index 863f9e0..c5c0d0c 100644 --- a/public/s/js/admin.js +++ b/public/s/js/admin.js @@ -1,41 +1,3 @@ -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 } ], { - duration: 500, - fill: "both" - } - ).onfinish = () => setTimeout(() => { - flashContainer.animate( - [ { bottom: 0 }, { bottom: "-28px" } ], { - duration: 500, - 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; @@ -140,10 +102,8 @@ const flash = ({ type, msg }) => { tagname: tmptag }); if(!res.success) { - return flash({ - type: "error", - msg: res.msg - }); + alert(res.msg); + return false; } tags = res.tags.map(t => t.tag); renderTags(res.tags); @@ -202,12 +162,6 @@ const flash = ({ type, msg }) => { })).json(); renderTags(res.tags); - tags = res.tags.map(t => t.tag); - - flash({ - type: "success", - msg: tags.join() - }); }; const deleteButtonEvent = async e => { @@ -218,17 +172,8 @@ const flash = ({ type, msg }) => { const res = await post("/api/v2/admin/deletepost", { postid: postid }); - if(res.success) { - flash({ - type: "success", - msg: "post was successfully deleted" - }); - } - else { - flash({ - type: "error", - msg: res.msg - }); + if(!res.success) { + alert(res.msg); } }; diff --git a/public/s/js/user.js b/public/s/js/user.js new file mode 100644 index 0000000..0c5e963 --- /dev/null +++ b/public/s/js/user.js @@ -0,0 +1,229 @@ +(async () => { + if(_addtag = document.querySelector("a#a_addtag")) { + const postid = +document.querySelector("a.id-link").innerText; + const poster = document.querySelector("a#a_username").innerText; + let tags = [...document.querySelectorAll("#tags > .badge")].map(t => t.innerText.slice(0, -2)); + + 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(); + }; + + const get = async (url, data) => queryapi(url, data, 'GET'); + const post = async (url, data) => queryapi(url, data, 'POST'); + + const renderTags = _tags => { + [...document.querySelectorAll("#tags > .badge")].forEach(tag => tag.parentElement.removeChild(tag)); + _tags.reverse().forEach(tag => { + const a = document.createElement("a"); + a.href = `/tag/${tag.normalized}`; + a.style = "color: inherit !important"; + a.innerHTML = tag.tag; + + const span = document.createElement("span"); + span.classList.add("badge", "mr-2"); + span.setAttribute('tooltip', tag.user); + + tag.badge.split(" ").forEach(b => span.classList.add(b)); + + span.insertAdjacentElement("beforeend", a); + + 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 = ""; + input.setAttribute("list", "testlist"); + input.setAttribute("autoComplete", "off"); + + span.insertAdjacentElement("afterbegin", input); + insert.insertAdjacentElement("beforebegin", span); + + input.focus(); + + let tt = null; + let lastInput = ''; + const testList = document.querySelector('#testlist'); + + input.addEventListener("keyup", async e => { + if(e.key === "Enter") { + const tmptag = input.value?.trim(); + if(tags.includes(tmptag)) + return alert("tag already exists"); + const res = await post("/api/v2/admin/" + postid + "/tags", { + tagname: tmptag + }); + if(!res.success) { + alert(res.msg); + return false; + } + tags = res.tags.map(t => t.tag); + renderTags(res.tags); + addtagClick(); + testList.innerText = ""; + } + else if(e.key === "Escape") { + span.parentElement.removeChild(span); + testList.innerText = ""; + } + else { + if(tt != null) + clearTimeout(tt); + + tt = setTimeout(async () => { + tt = null; + + const tmptag = input.value?.trim(); + + if(tmptag == lastInput || tmptag.length <= 1) + return false; + + testList.innerText = ""; + lastInput = tmptag; + + const res = await get('/api/v2/admin/tags/suggest', { + q: tmptag + }); + + for(const entry of res.suggestions) { + const option = document.createElement('option'); + option.value = entry.tag; + + if(!/fox/.test(navigator.userAgent)) + option.innerText = `tagged ${entry.tagged} times (score: ${entry.score.toFixed(2)})`; + + testList.insertAdjacentElement('beforeEnd', option); + }; + }, 500); + } + return true; + }); + + input.addEventListener("focusout", ie => { + if(input.value.length === 0) + input.parentElement.parentElement.removeChild(input.parentElement); + }); + }; + + const toggleEvent = async (e = false) => { + if(e) + e.preventDefault(); + + const res = await (await fetch('/api/v2/admin/' + encodeURIComponent(postid) + '/tags/toggle', { + method: 'PUT' + })).json(); + + renderTags(res.tags); + }; + + const toggleFavEvent = async e => { + const res = await post('/api/v2/admin/togglefav', { + postid: postid + }); + 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'); + favcontainer.innerHTML = ""; + + favcontainer.hidden = !(favcontainer.hidden || res.favs.length > 0); + + res.favs.forEach(f => { + const a = document.createElement('a'); + a.href = `/user/${f.user}/favs`; + a.setAttribute('tooltip', f.user); + a.setAttribute('flow', 'up'); + + const img = document.createElement('img'); + img.src = `/t/${f.avatar}.webp`; + img.style.height = "32px"; + img.style.width = "32px"; + + a.insertAdjacentElement('beforeend', img); + favcontainer.insertAdjacentElement('beforeend', a); + favcontainer.innerHTML += " "; + }); + } + else { + // lul + } + }; + + _addtag.addEventListener("click", addtagClick); + document.querySelector("a#a_toggle").addEventListener("click", toggleEvent); + document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent); + + 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(); + else if(e.key === "f") + toggleFavEvent(); + }); + } + + if(document.location.pathname === '/settings') { + const saveAvatar = async e => { + e.preventDefault(); + + 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); + }); + } +})(); diff --git a/views/snippets/footer.html b/views/snippets/footer.html index 9b7b35f..68f5ac9 100644 --- a/views/snippets/footer.html +++ b/views/snippets/footer.html @@ -1,7 +1,11 @@ - @if(session)@endif + @if(session)
{{ JSON.stringify(session) }}
@endif - @if(session)@endif + @if(session && session.admin) + + @elseif(session && !session.admin) + + @endif