a6a730649d
FossilOrigin-Name: 6f5b19c5b79c90365430be17127185a22c1a709e6666f405869525c701a17d22
351 lines
10 KiB
JavaScript
351 lines
10 KiB
JavaScript
"use strict";
|
|
|
|
// Helper function for manipulating the DOM / creating DOM elements
|
|
function em(tag, values, child)
|
|
{
|
|
let element = document.createElement(tag);
|
|
|
|
// Can either be a "append"-able type, or properties
|
|
// If it's properties, then child must be set
|
|
if ((typeof values === 'string' ||
|
|
values instanceof HTMLElement) && !child)
|
|
{
|
|
element.append(element);
|
|
}
|
|
else if (typeof values === 'number') {
|
|
element.append(values.toString());
|
|
}
|
|
else if (typeof values === 'object' && child) {
|
|
for (const prop in values)
|
|
{
|
|
element[prop] = values[prop];
|
|
}
|
|
} // ???
|
|
|
|
// Type doesn't matter, just append whatever is in child
|
|
if (child)
|
|
{
|
|
// Well, except if it's a string
|
|
if (typeof values === 'number')
|
|
element.append(child.toString());
|
|
else
|
|
element.append(child);
|
|
}
|
|
|
|
return element;
|
|
}
|
|
|
|
function get_cookie(cookiestr)
|
|
{
|
|
return document.cookie
|
|
.split(';')
|
|
.find(row => row.startsWith(cookiestr+'='))
|
|
.split('=')[1];
|
|
}
|
|
|
|
// TODO Check if logged in .acct value is the same
|
|
function reply_get_mentions(reply, content)
|
|
{
|
|
const regexpr = /<a target="_parent" class="mention" href="https?:\/\/.*?\/@(.*?)@(.*?)">.*?<\/a>/g;
|
|
const arr = [...content.matchAll(regexpr)];
|
|
let res = reply ? `@${reply} ` : "";
|
|
const matches = content.matchAll(regexpr);
|
|
|
|
for (let x of matches)
|
|
{
|
|
res += `@${x[1]}@${x[2]} `;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
function form_enter_submit(e, that)
|
|
{
|
|
if ((e.ctrlKey || e.metaKey) && e.keyCode === 13)
|
|
that.closest('form').submit();
|
|
}
|
|
|
|
// Submit form entry on enter when in textbox/textarea
|
|
document.querySelectorAll("input[type=text], input[type=url], input[type=email], input[type=password], textarea").forEach((i) => {
|
|
i.addEventListener("keydown", e => form_enter_submit(e, i));
|
|
});
|
|
|
|
function construct_query(query)
|
|
{
|
|
let query_string = "";
|
|
let keys = Object.keys(query);
|
|
let vals = Object.values(query);
|
|
const len = keys.length;
|
|
|
|
for (let i = 0; i < keys.length; ++i)
|
|
{
|
|
query_string += keys[i] + "=" + vals[i];
|
|
if (i !== keys.length-1)
|
|
query_string += "&";
|
|
}
|
|
return query_string;
|
|
}
|
|
|
|
function send_request(url, query, type, cb, cb_args)
|
|
{
|
|
let query_str = construct_query(query);
|
|
let xhr = new XMLHttpRequest();
|
|
xhr.open(type, url);
|
|
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
xhr.onreadystatechange = function() {
|
|
if (this.readyState === XMLHttpRequest.DONE)
|
|
cb(this, cb_args);
|
|
};
|
|
xhr.send(query_str);
|
|
return xhr;
|
|
}
|
|
|
|
function upload_file(url, file_name, file, cb, cb_args, onprogress, onload)
|
|
{
|
|
let xhr = new XMLHttpRequest();
|
|
let form_data = new FormData();
|
|
xhr.open("post", url);
|
|
form_data.append(file_name, file);
|
|
// xhr.setRequestHeader("Content-Type", "multipart/form-data");
|
|
xhr.onreadystatechange = function() {
|
|
if (this.readyState === XMLHttpRequest.DONE)
|
|
cb(this, cb_args);
|
|
};
|
|
xhr.upload.onprogress = onprogress;
|
|
xhr.upload.onload = onload;
|
|
xhr.send(form_data);
|
|
return xhr;
|
|
}
|
|
|
|
function change_count_text(val, sum)
|
|
{
|
|
if (val === "")
|
|
val = 0
|
|
else
|
|
val = parseInt(val);
|
|
val += sum;
|
|
return val > 0 ? val.toString() : "";
|
|
}
|
|
|
|
function interact_action(status, type)
|
|
{
|
|
let like = status.querySelector(".statbtn .like");
|
|
let repeat = status.querySelector(".statbtn .repeat");
|
|
|
|
let svg;
|
|
if (type.value === "like" || type.value === "unlike")
|
|
svg = [ like ];
|
|
else if (type.value === "repeat" || type.value === "unrepeat")
|
|
svg = [ repeat ];
|
|
else if (type.value === "likeboost")
|
|
svg = [ like, repeat ];
|
|
|
|
if (svg)
|
|
svg.forEach(that => {
|
|
let label = that.parentNode;
|
|
let counter = label.querySelector(".count");
|
|
let is_interacted = label.classList.contains("interacted");
|
|
|
|
if (counter)
|
|
{
|
|
counter.innerHTML = change_count_text(counter.innerHTML, is_interacted ? -1 : 1);
|
|
}
|
|
else {
|
|
// Nobody interacted with this yet, create counter
|
|
const counter = em("span", { className: "count" }, 1)
|
|
label.append(counter);
|
|
is_interacted = false;
|
|
}
|
|
|
|
if (is_interacted)
|
|
{
|
|
// Animation
|
|
that.classList.remove("interacted-anim");
|
|
label.classList.remove("interacted");
|
|
|
|
// Flip itype value
|
|
type.value = type.value.replace("un", "");
|
|
}
|
|
else {
|
|
that.classList.add("interacted-anim");
|
|
label.classList.add("interacted");
|
|
type.value = "un" + type.value;
|
|
}
|
|
});
|
|
}
|
|
|
|
function status_event(e)
|
|
{
|
|
let target = e.target.closest(".statbtn");
|
|
if (target)
|
|
{
|
|
console.log('huh');
|
|
// Don't JS these
|
|
if (target.classList.contains("reply-btn") ||
|
|
target.classList.contains("view-btn") ||
|
|
target.classList.contains("statbtn-last"))
|
|
return true;
|
|
let type = target.parentNode.querySelector(".itype");
|
|
let status = e.target.closest(".status");
|
|
|
|
send_request("/treebird_api/v1/interact",
|
|
{
|
|
id: status.id,
|
|
itype: type.value
|
|
},
|
|
"POST",
|
|
(xhr, args) => {
|
|
if (xhr.status !== 200)
|
|
{
|
|
// Undo action if failure
|
|
interact_action(status, type);
|
|
}
|
|
}, null);
|
|
|
|
interact_action(status, type);
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function frame_resize()
|
|
{
|
|
let rightbar_frame = document.querySelector("#rightbar .sidebar-frame");
|
|
let rbar_frame_win = rightbar_frame.contentWindow;
|
|
rightbar_frame.height = rbar_frame_win.document.body.scrollHeight;
|
|
}
|
|
|
|
function filesize_to_str(bs)
|
|
{
|
|
const val = bs === 0 ? 0 : Math.floor(Math.log(bs) / Math.log(1024));
|
|
return (bs / 1024**val).toFixed(1) * 1 + ['B', 'kB', 'MB', 'GB', 'TB'][val];
|
|
}
|
|
|
|
function html_encode(str)
|
|
{
|
|
let en = document.createElement("span");
|
|
en.textContent = str;
|
|
return en.innerHTML;
|
|
}
|
|
|
|
function construct_file_upload(file, file_content)
|
|
{
|
|
let container = document.createElement("div");
|
|
let content = document.createElement("img");
|
|
let info = document.createElement("span");
|
|
container.className = "file-upload";
|
|
|
|
info.className = "upload-info";
|
|
info.innerHTML = `<span class="filesize">${filesize_to_str(file.size)}</span> • <span class="filename">${html_encode(file.name)}</span>`;
|
|
let progress_div = document.createElement("div");
|
|
progress_div.className = "file-progress";
|
|
info.appendChild(progress_div);
|
|
|
|
content.src = file_content;
|
|
content.className = "upload-content";
|
|
|
|
container.appendChild(content);
|
|
container.appendChild(info);
|
|
return container;
|
|
}
|
|
|
|
function update_uploads_json(dom)
|
|
{
|
|
let root = dom.parentNode;
|
|
let items = root.getElementsByClassName("file-upload");
|
|
let ids = [];
|
|
|
|
for (let i of items)
|
|
{
|
|
if (i.dataset.id)
|
|
ids.push(i.dataset.id);
|
|
}
|
|
|
|
// Goto statusbox
|
|
root = root.parentNode;
|
|
let file_ids = root.querySelector(".file-ids-json");
|
|
if (!file_ids)
|
|
{
|
|
// Create if doesn't exist
|
|
file_ids = document.createElement("input");
|
|
file_ids.type = "hidden";
|
|
file_ids.className = "file-ids-json";
|
|
file_ids.name = "fileids";
|
|
root.appendChild(file_ids);
|
|
}
|
|
|
|
file_ids.value = JSON.stringify(ids);
|
|
}
|
|
|
|
function evt_file_upload(e)
|
|
{
|
|
let target = e.target;
|
|
let file_upload_dom = this.closest("form").querySelector(".file-uploads-container");
|
|
file_upload_dom.className = "file-uploads-container";
|
|
const files = [...this.files];
|
|
|
|
let reader;
|
|
|
|
// Clear file input
|
|
this.value = '';
|
|
|
|
// Create file upload
|
|
for (let file of files)
|
|
{
|
|
reader = new FileReader();
|
|
reader.onload = (() => {
|
|
return (e) => {
|
|
let file_dom = construct_file_upload(file, e.target.result);
|
|
|
|
file_upload_dom.appendChild(file_dom);
|
|
|
|
let xhr = upload_file("/treebird_api/v1/attachment",
|
|
"file",
|
|
file,
|
|
(xhr, args) => {
|
|
// TODO errors
|
|
file_dom.dataset.id = JSON.parse(xhr.response).id;
|
|
update_uploads_json(file_dom);
|
|
}, null,
|
|
(e) => {
|
|
let upload_file_progress = file_dom
|
|
.querySelector(".file-progress");
|
|
// Add offset of 3
|
|
upload_file_progress.style.width = 3+((e.loaded/e.total)*97);
|
|
},
|
|
(e) => {
|
|
file_dom.querySelector(".upload-content").style.opacity = "1.0";
|
|
file_dom.querySelector(".file-progress").remove();
|
|
});
|
|
}
|
|
})(file);
|
|
reader.readAsDataURL(file);
|
|
|
|
}
|
|
}
|
|
|
|
// Main (when loaded)
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
let interact_btn = document.getElementsByClassName("status");
|
|
|
|
// Add event listener to add specificied buttons
|
|
for (let i = 0; i < interact_btn.length; ++i)
|
|
{
|
|
interact_btn[i].addEventListener('click', status_event);
|
|
}
|
|
|
|
// Resize notifications iFrame to full height
|
|
let rightbar_frame = document.querySelector("#rightbar .sidebar-frame");
|
|
if (rightbar_frame)
|
|
{
|
|
rightbar_frame.contentWindow.addEventListener('DOMContentLoaded', frame_resize);
|
|
}
|
|
|
|
// File upload
|
|
let file_inputs = document.querySelectorAll(".statusbox input[type=file]");
|
|
for (let file_input of file_inputs)
|
|
{
|
|
file_input.addEventListener('change', evt_file_upload);
|
|
}
|
|
});
|