user/admin blah
blah
This commit is contained in:
		@@ -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);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										229
									
								
								public/s/js/user.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								public/s/js/user.js
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
})();
 | 
			
		||||
@@ -1,7 +1,11 @@
 | 
			
		||||
  @if(session)<!--<div style="position: fixed; bottom: 0; z-index: 998; background-color: var(--bg); width: 100%; height: 29px; border-top: 1px solid var(--accent)">{{ JSON.stringify(session) }}</div>-->@endif
 | 
			
		||||
  @if(session)<div style="position: fixed; bottom: 0; z-index: 998; background-color: var(--bg); width: 100%; height: 29px; border-top: 1px solid var(--accent)">{{ JSON.stringify(session) }}</div>@endif
 | 
			
		||||
  <script async src="/s/js/theme.js?v=@mtime(/public/s/js/theme.js)"></script>
 | 
			
		||||
  <script src="/s/js/v0ck.js?v=@mtime(/public/s/js/v0ck.js)"></script>
 | 
			
		||||
  <script src="/s/js/f0ck.js?v=@mtime(/public/s/js/f0ck.js)"></script>
 | 
			
		||||
  @if(session)<script src="/s/js/admin.js?v=@mtime(/public/s/js/admin.js)"></script>@endif
 | 
			
		||||
  @if(session && session.admin)
 | 
			
		||||
    <script src="/s/js/admin.js?v=@mtime(/public/s/js/admin.js)"></script>
 | 
			
		||||
  @elseif(session && !session.admin)
 | 
			
		||||
    <script src="/s/js/user.js?v=@mtime(/public/s/js/user.js)"></script>
 | 
			
		||||
  @endif
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user