forked from mirrors/treebird
Resize notifications frame
FossilOrigin-Name: 482443d0c2140deef0f1b5682d5fe35dda95dec752812b0dab4764c3835bb537
This commit is contained in:
parent
f4fcb0dfa7
commit
afe85ce1ae
3 changed files with 250 additions and 225 deletions
462
dist/js/main.js
vendored
462
dist/js/main.js
vendored
|
@ -1,246 +1,266 @@
|
|||
Element.prototype.insertAfter = function(element) {
|
||||
element.parentNode.insertBefore(this, element.nextSibling);
|
||||
};
|
||||
(function(){
|
||||
Element.prototype.insertAfter = function(element) {
|
||||
element.parentNode.insertBefore(this, element.nextSibling);
|
||||
};
|
||||
|
||||
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)
|
||||
function get_cookie(cookiestr)
|
||||
{
|
||||
res += `@${x[1]}@${x[2]} `;
|
||||
return document.cookie
|
||||
.split(';')
|
||||
.find(row => row.startsWith(cookiestr+'='))
|
||||
.split('=')[1];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function form_enter_submit(e, that)
|
||||
{
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode === 13)
|
||||
that.closest('form').submit();
|
||||
}
|
||||
// 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);
|
||||
|
||||
// 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_quick_reply_form(status)
|
||||
{
|
||||
let src = document.createElement("form");
|
||||
src.action = "/status/create";
|
||||
src.method = "post";
|
||||
src.enctype = "multipart/form-data";
|
||||
src.className = "statusbox-quickreply";
|
||||
let hiddeninput = document.createElement("input");
|
||||
hiddeninput.type = "hidden";
|
||||
hiddeninput.name = "replyid"
|
||||
hiddeninput.value = status.id;
|
||||
let statusbox = document.createElement("div");
|
||||
statusbox.className = "statusbox statusbox-ani";
|
||||
|
||||
let textarea = document.createElement("textarea");
|
||||
textarea.placeholder = "Just landed in N.Y.";
|
||||
textarea.rows = 5;
|
||||
textarea.tabindex = 1;
|
||||
textarea.name = "content";
|
||||
|
||||
// Load placeholder text
|
||||
let instance_info = status.querySelector(".instance-info");
|
||||
textarea.innerText = reply_get_mentions(
|
||||
instance_info ? instance_info.innerText : null,
|
||||
status.querySelector(".status-content").innerHTML
|
||||
);
|
||||
|
||||
let statusfooter = document.createElement("div");
|
||||
statusfooter.className = "statusfooter";
|
||||
let statusfooter_sides = {
|
||||
left: document.createElement("div"),
|
||||
right: document.createElement("div"),
|
||||
for (let x of matches)
|
||||
{
|
||||
res += `@${x[1]}@${x[2]} `;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
let select = document.createElement("select");
|
||||
let files_input = document.createElement("input");
|
||||
statusfooter_sides.left.className = "statusfooter-left";
|
||||
select.innerHTML = `
|
||||
|
||||
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_quick_reply_form(status)
|
||||
{
|
||||
let src = document.createElement("form");
|
||||
src.action = "/status/create";
|
||||
src.method = "post";
|
||||
src.enctype = "multipart/form-data";
|
||||
src.className = "statusbox-quickreply";
|
||||
let hiddeninput = document.createElement("input");
|
||||
hiddeninput.type = "hidden";
|
||||
hiddeninput.name = "replyid"
|
||||
hiddeninput.value = status.id;
|
||||
let statusbox = document.createElement("div");
|
||||
statusbox.className = "statusbox statusbox-ani";
|
||||
|
||||
let textarea = document.createElement("textarea");
|
||||
textarea.placeholder = "Just landed in N.Y.";
|
||||
textarea.rows = 5;
|
||||
textarea.tabindex = 1;
|
||||
textarea.name = "content";
|
||||
|
||||
// Load placeholder text
|
||||
let instance_info = status.querySelector(".instance-info");
|
||||
textarea.innerText = reply_get_mentions(
|
||||
instance_info ? instance_info.innerText : null,
|
||||
status.querySelector(".status-content").innerHTML
|
||||
);
|
||||
|
||||
let statusfooter = document.createElement("div");
|
||||
statusfooter.className = "statusfooter";
|
||||
let statusfooter_sides = {
|
||||
left: document.createElement("div"),
|
||||
right: document.createElement("div"),
|
||||
}
|
||||
let select = document.createElement("select");
|
||||
let files_input = document.createElement("input");
|
||||
statusfooter_sides.left.className = "statusfooter-left";
|
||||
select.innerHTML = `
|
||||
<option value="public">Public</option>
|
||||
<option value="unlisted">Unlisted</option>
|
||||
<option value="private">Private</option>
|
||||
<option value="direct">Direct</option>
|
||||
<option value="local">Local</option>
|
||||
`.trim();
|
||||
files_input.type = "file";
|
||||
files_input.name = "file";
|
||||
files_input.tabindex = 4;
|
||||
files_input.multiple = "";
|
||||
files_input.type = "file";
|
||||
files_input.name = "file";
|
||||
files_input.tabindex = 4;
|
||||
files_input.multiple = "";
|
||||
|
||||
statusfooter_sides.right.className = "statusfooter-right";
|
||||
let submitbtn = document.createElement("input");
|
||||
submitbtn.className = "btn post-btn";
|
||||
submitbtn.type = "submit";
|
||||
submitbtn.value = "Post";
|
||||
submitbtn.tabindex = 2;
|
||||
statusfooter_sides.right.className = "statusfooter-right";
|
||||
let submitbtn = document.createElement("input");
|
||||
submitbtn.className = "btn post-btn";
|
||||
submitbtn.type = "submit";
|
||||
submitbtn.value = "Post";
|
||||
submitbtn.tabindex = 2;
|
||||
|
||||
|
||||
statusfooter_sides.left.appendChild(select);
|
||||
statusfooter_sides.left.appendChild(files_input);
|
||||
statusfooter_sides.right.appendChild(submitbtn);
|
||||
statusfooter.appendChild(statusfooter_sides.left);
|
||||
statusfooter.appendChild(statusfooter_sides.right);
|
||||
statusbox.appendChild(textarea);
|
||||
textarea.addEventListener("keydown", e => form_enter_submit(e, textarea));
|
||||
statusbox.appendChild(statusfooter);
|
||||
src.appendChild(hiddeninput);
|
||||
src.appendChild(statusbox);
|
||||
return src;
|
||||
}
|
||||
|
||||
function construct_query(query)
|
||||
{
|
||||
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 += "&";
|
||||
|
||||
statusfooter_sides.left.appendChild(select);
|
||||
statusfooter_sides.left.appendChild(files_input);
|
||||
statusfooter_sides.right.appendChild(submitbtn);
|
||||
statusfooter.appendChild(statusfooter_sides.left);
|
||||
statusfooter.appendChild(statusfooter_sides.right);
|
||||
statusbox.appendChild(textarea);
|
||||
textarea.addEventListener("keydown", e => form_enter_submit(e, textarea));
|
||||
statusbox.appendChild(statusfooter);
|
||||
src.appendChild(hiddeninput);
|
||||
src.appendChild(statusbox);
|
||||
return src;
|
||||
}
|
||||
return query_string;
|
||||
}
|
||||
|
||||
function send_request(url, query, type, cb, cb_args)
|
||||
{
|
||||
let query_str = construct_query(query);
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", 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);
|
||||
}
|
||||
function construct_query(query)
|
||||
{
|
||||
query_string = "";
|
||||
let keys = Object.keys(query);
|
||||
let vals = Object.values(query);
|
||||
const len = keys.length;
|
||||
|
||||
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 ];
|
||||
|
||||
svg.forEach(that => {
|
||||
let label = that.parentNode;
|
||||
let counter = label.querySelector(".count");
|
||||
|
||||
let is_active = that.classList.contains("active");
|
||||
|
||||
that.classList.toggle("active");
|
||||
|
||||
|
||||
if (is_active)
|
||||
for (let i = 0; i < keys.length; ++i)
|
||||
{
|
||||
// Animation
|
||||
that.classList.remove("active-anim");
|
||||
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("POST", 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);
|
||||
}
|
||||
|
||||
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 ];
|
||||
|
||||
svg.forEach(that => {
|
||||
let label = that.parentNode;
|
||||
let counter = label.querySelector(".count");
|
||||
|
||||
// Flip itype value
|
||||
type.value = type.value.replace("un", "");
|
||||
let is_active = that.classList.contains("active");
|
||||
|
||||
that.classList.toggle("active");
|
||||
|
||||
|
||||
if (is_active)
|
||||
{
|
||||
// Animation
|
||||
that.classList.remove("active-anim");
|
||||
|
||||
// Flip itype value
|
||||
type.value = type.value.replace("un", "");
|
||||
}
|
||||
else {
|
||||
that.classList.add("active-anim");
|
||||
type.value = "un" + type.value;
|
||||
}
|
||||
|
||||
counter.innerHTML = change_count_text(counter.innerHTML, is_active ? -1 : 1);
|
||||
});
|
||||
}
|
||||
|
||||
function status_interact_props(e)
|
||||
{
|
||||
let interact = e.target.closest(".statbtn");
|
||||
let type = interact.parentNode.querySelector(".itype");
|
||||
if (type === null)
|
||||
return true;
|
||||
let status = interact.closest(".status");
|
||||
|
||||
send_request("/treebird_api/v1/interact",
|
||||
{
|
||||
id: status.id,
|
||||
itype: type.value
|
||||
},
|
||||
1,
|
||||
(xhr, args) => {
|
||||
if (xhr.status !== 200)
|
||||
{
|
||||
// Undo action if failure
|
||||
interact_action(status, type);
|
||||
}
|
||||
}, null);
|
||||
|
||||
interact_action(status, type);
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function create_reply_form(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
let status = e.target.closest(".status");
|
||||
|
||||
if (status.nextSibling.className === "statusbox-quickreply")
|
||||
{
|
||||
status.nextSibling.remove();
|
||||
}
|
||||
else {
|
||||
that.classList.add("active-anim");
|
||||
type.value = "un" + type.value;
|
||||
let form = construct_quick_reply_form(status);
|
||||
form.insertAfter(status);
|
||||
}
|
||||
|
||||
counter.innerHTML = change_count_text(counter.innerHTML, is_active ? -1 : 1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Main (when loaded)
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
let reply_btn = document.getElementsByClassName("reply-btn");
|
||||
let interact_btn = document.getElementsByClassName("statbtn");
|
||||
|
||||
// Add event listener to add specificied buttons
|
||||
for (let i = 0; i < reply_btn.length; ++i)
|
||||
{
|
||||
reply_btn[i].addEventListener('click', create_reply_form);
|
||||
}
|
||||
for (let i = 0; i < interact_btn.length; ++i)
|
||||
{
|
||||
interact_btn[i].addEventListener('click', status_interact_props);
|
||||
}
|
||||
|
||||
// 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_input = document.querySelector("input[type=file]");
|
||||
});
|
||||
}
|
||||
|
||||
function status_interact_props(e)
|
||||
{
|
||||
let interact = e.target.closest(".statbtn");
|
||||
let type = interact.parentNode.querySelector(".itype");
|
||||
if (type === null)
|
||||
return true;
|
||||
let status = interact.closest(".status");
|
||||
|
||||
send_request("/treebird_api/v1/interact",
|
||||
{
|
||||
id: status.id,
|
||||
itype: type.value
|
||||
},
|
||||
1,
|
||||
(xhr, args) => {
|
||||
if (xhr.status !== 200)
|
||||
{
|
||||
// Undo action if failure
|
||||
interact_action(status, type);
|
||||
}
|
||||
}, null);
|
||||
|
||||
interact_action(status, type);
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function create_reply_form(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
let status = e.target.closest(".status");
|
||||
|
||||
if (status.nextSibling.className === "statusbox-quickreply")
|
||||
{
|
||||
status.nextSibling.remove();
|
||||
}
|
||||
else {
|
||||
let form = construct_quick_reply_form(status);
|
||||
form.insertAfter(status);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Main
|
||||
(function() {
|
||||
let reply_btn = document.getElementsByClassName("reply-btn");
|
||||
let interact_btn = document.getElementsByClassName("statbtn");
|
||||
|
||||
for (let i = 0; i < reply_btn.length; ++i)
|
||||
{
|
||||
reply_btn[i].addEventListener('click', create_reply_form);
|
||||
}
|
||||
|
||||
for (let i = 0; i < interact_btn.length; ++i)
|
||||
{
|
||||
interact_btn[i].addEventListener('click', status_interact_props);
|
||||
}
|
||||
})();
|
||||
|
|
5
dist/treebird.css
vendored
5
dist/treebird.css
vendored
|
@ -456,6 +456,11 @@ select
|
|||
min-width: 100px;
|
||||
}
|
||||
|
||||
select:hover
|
||||
{
|
||||
background: linear-gradient(#f0f0f0, #d0d0d0);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* BUTTONS *
|
||||
*************************************************/
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<form action="{{%s:prefix}}/status/create" method="post" enctype="multipart/form-data">
|
||||
{{%s:reply_input}}
|
||||
<div class="statusbox">
|
||||
<textarea name="content" placeholder="Just landed in N.Y." rows="5" tabindex="1">{{%s:content}}</textarea>
|
||||
<textarea name="content" placeholder="Just landed in N.Y." rows="5">{{%s:content}}</textarea>
|
||||
<div class="statusfooter">
|
||||
<div class="statusfooter-left">
|
||||
<label>
|
||||
<input type="file" name="file" class="hidden" tabindex="4" multiple>
|
||||
<input type="file" name="file" class="hidden" multiple>
|
||||
<div class="file-upload-btn btn-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg>
|
||||
</div>
|
||||
</label>
|
||||
<select tabindex="3" name="contenttype" class="content-type">
|
||||
<select name="contenttype" class="content-type">
|
||||
<option value="plaintext">Plain Text</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
<option value="html">HTML</option>
|
||||
|
@ -55,7 +55,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="statusfooter-right">
|
||||
<input type="submit" value="Post" tabindex="2" class="btn post-btn">
|
||||
<input type="submit" value="Post" class="btn post-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue