refactor file upload

pull/136/head
Aevann 2023-02-27 17:02:35 +02:00
parent 9559c6e93a
commit 5b71b0a81a
19 changed files with 276 additions and 253 deletions

View File

@ -142,6 +142,16 @@ function register_new_elements(e) {
document.getElementById(element.dataset.toggleelement).classList.toggle(element.dataset.toggleattr);
});
}
const file_inputs = document.querySelectorAll('input[type="file"]')
for (const input of file_inputs) {
input.onchange = () => {handle_files(input, input.files)};
}
const remove_files = document.querySelectorAll('button.remove-files')
for (const element of remove_files) {
element.onclick = () => {cancel_files(element)};
}
}
register_new_elements(document);

View File

@ -147,8 +147,9 @@ socket.on('speak', function(json) {
})
function send() {
const text = textbox.value.trim()
const files = document.getElementById('file').files
const text = textbox.value.trim();
const input = document.getElementById('file');
const files = input.files;
if (text || files)
{
let sending;
@ -166,7 +167,9 @@ function send() {
document.getElementById("quotes").classList.add("d-none")
document.getElementById('quotes_id').value = null;
document.getElementById("filename").innerHTML = '<i class="fas fa-image" style="font-size:1.3rem!important"></i>'
document.getElementById('file').value = null;
input.value = null;
input.parentElement.nextElementSibling.classList.add('d-none');
box.scrollTo(0, box.scrollHeight);
setTimeout(function () {
box.scrollTo(0, box.scrollHeight)
@ -294,20 +297,6 @@ document.addEventListener('click', function (e) {
}
});
document.onpaste = function(event) {
files = structuredClone(event.clipboardData.files);
filename = files[0]
if (filename)
{
filename = filename.name.toLowerCase()
f=document.getElementById('file');
f.files = files;
document.getElementById('filename').textContent = filename;
}
}
box.scrollTo(0, box.scrollHeight)
setTimeout(function () {
box.scrollTo(0, box.scrollHeight)

View File

@ -51,7 +51,7 @@ function getSelectionTextHtml() {
function toggleReplyBox(id) {
const element = document.getElementById(id);
const textarea = element.getElementsByTagName('textarea')[0]
const ta = element.getElementsByTagName('textarea')[0]
element.classList.toggle('d-none')
if (!element.classList.contains('d-none'))
@ -64,12 +64,12 @@ function toggleReplyBox(id) {
text = text.replace(/\n> \n/g,"\n \n")
text = text.split('> Reply')[0]
if (!text.endsWith('\n')) text += '\n'
textarea.value = text
ta.value = text
}
textarea.focus()
ta.focus()
}
autoExpand(textarea);
autoExpand(ta);
}
function toggleEdit(id){
@ -116,7 +116,9 @@ function post_reply(id){
const form = new FormData();
form.append('parent_id', id);
form.append('body', document.getElementById('reply-form-body-'+id).value);
const ta = document.getElementById('reply-form-body-'+id)
form.append('body', ta.value);
try {
for (const e of document.getElementById(`file-upload-reply-c_${id}`).files)
form.append('file', e);
@ -140,14 +142,15 @@ function post_reply(id){
btn.disabled = false;
btn.classList.remove('disabled');
document.getElementById('reply-form-body-'+id).value = ''
ta.value = ''
document.getElementById('message-reply-'+id).innerHTML = ''
toggleReplyBox('reply-message-c_'+id)
const fileupload = document.getElementById(`file-upload-reply-c_${id}`)
if (fileupload) {
fileupload.value = null;
document.getElementById(`filename-show-reply-c_${id}`).innerHTML = '<i class="fas fa-file"></i>';
}
const input = ta.parentElement.querySelector('input[type="file"]')
input.previousElementSibling.innerHTML = '';
input.value = null;
input.parentElement.nextElementSibling.classList.add('d-none');
oldfiles[ta.id] = []
} else {
showToast(false, getMessageFromJsonData(false, data));
}
@ -164,8 +167,10 @@ function comment_edit(id){
btn.disabled = true
btn.classList.add('disabled');
const ta = document.getElementById('comment-edit-body-'+id)
const form = new FormData();
form.append('body', document.getElementById('comment-edit-body-'+id).value);
form.append('body', ta.value);
try {
for (const e of document.getElementById('file-edit-reply-'+id).files)
@ -185,9 +190,13 @@ function comment_edit(id){
register_new_elements(commentForm);
bs_trigger(commentForm);
document.getElementById('filename-edit-reply-' + id).innerHTML = '<i class="fas fa-file"></i>';
document.getElementById('comment-edit-body-' + id).value = data["body"];
document.getElementById('file-edit-reply-'+id).value = null;
const input = ta.parentElement.querySelector('input[type="file"]')
input.previousElementSibling.innerHTML = '';
input.value = null;
input.parentElement.nextElementSibling.classList.add('d-none');
oldfiles[ta.id] = []
}
else {
showToast(false, getMessageFromJsonData(false, data));
@ -202,7 +211,7 @@ function comment_edit(id){
function post_comment(fullname, hide){
const btn = document.getElementById('save-reply-to-'+fullname)
const textArea = document.getElementById('reply-form-body-'+fullname)
const ta = document.getElementById('reply-form-body-'+fullname)
btn.disabled = true
btn.classList.add('disabled');
@ -210,7 +219,7 @@ function post_comment(fullname, hide){
form.append('formkey', formkey());
form.append('parent_fullname', fullname);
form.append('body', textArea.value);
form.append('body', ta.value);
try {
for (const e of document.getElementById('file-upload-reply-'+fullname).files)
@ -243,12 +252,17 @@ function post_comment(fullname, hide){
btn.disabled = false;
btn.classList.remove('disabled');
document.getElementById('reply-form-body-'+fullname).value = ''
ta.value = ''
autoExpand(ta);
document.getElementById('form-preview-'+fullname).innerHTML = ''
document.getElementById('charcount-'+fullname).innerHTML = ''
document.getElementById('filename-show-reply-' + fullname).innerHTML = '<i class="fas fa-file"></i>';
document.getElementById('file-upload-reply-'+fullname).value = null;
autoExpand(textArea);
const input = ta.parentElement.querySelector('input[type="file"]')
input.previousElementSibling.innerHTML = '';
input.value = null;
input.parentElement.nextElementSibling.classList.add('d-none');
oldfiles[ta.id] = []
}
else {
showToast(false, getMessageFromJsonData(false, data));
@ -261,42 +275,6 @@ function post_comment(fullname, hide){
xhr.send(form)
}
document.onpaste = function(event) {
const focused = document.activeElement;
const files = structuredClone(event.clipboardData.files);
if (!files.length) return
if (focused.id.includes('reply-form-body-')) {
const fullname = focused.dataset.fullname;
f=document.getElementById('file-upload-reply-' + fullname);
f.files = files;
changename('filename-show-reply-' + fullname, f.id, focused.id)
}
else if (focused.id.includes('comment-edit-body-')) {
const id = focused.dataset.id;
f=document.getElementById('file-edit-reply-' + id);
f.files = files;
changename('filename-edit-reply-' + id, f.id, focused.id)
}
else if (focused.id.includes('post-edit-box-')) {
const id = focused.dataset.id;
f=document.getElementById('file-upload-edit-' + id);
f.files = files;
changename('filename-show-edit-' + id, f.id, focused.id)
}
else if (focused.id == "input-message") {
f=document.getElementById('file-upload');
f.files = files;
changename('filename', f.id, focused.id)
}
else if (focused.id == "input-message-mobile") {
f=document.getElementById('file-upload-mobile');
f.files = files;
changename('filename-mobile', f.id, focused.id)
}
}
function handle_action(type, cid, thing) {
const btns = document.getElementsByClassName(`action-${cid}`)
for (const btn of btns)

View File

@ -1,9 +0,0 @@
document.onpaste = function(event) {
const files = structuredClone(event.clipboardData.files);
if (!files.length) return
const f = document.getElementById('file-upload');
f.files = files;
changename('filename', f.id, 'input-message')
}

View File

@ -114,7 +114,7 @@ function postToastSwitch(t, url, button1, button2, cls, extraActionsOnSuccess, m
, method);
}
if (location.pathname != '/submit')
if (!location.pathname.endsWith('/submit'))
{
document.addEventListener('keydown', (e) => {
if(!((e.ctrlKey || e.metaKey) && e.key === "Enter")) return;
@ -244,34 +244,6 @@ function escapeHTML(unsafe) {
return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
}
function changename(s1,s2,textarea) {
const files = document.getElementById(s2).files;
if (files.length > 8)
{
alert("You can't upload more than 8 files at one time!")
document.getElementById(s2).value = null
return
}
const ta = document.getElementById(textarea);
ta.value = ta.value.replace(/[file]\n/g, "")
if (ta.value) {
ta.value += '\n'
}
let filename = '';
for (const e of files) {
filename += e.name.substr(0, 22) + ', ';
ta.value += '[file]\n'
}
document.getElementById(s1).innerHTML = escapeHTML(filename.slice(0, -2));
console.log(ta)
autoExpand(ta)
ta.focus()
ta.selectionStart = ta.selectionEnd = ta.value.length;
}
function showmore(t) {
let div = t
while (!(div.id && (div.id.startsWith('comment-text-') || div.id == 'post-text'))){
@ -466,3 +438,139 @@ function focusSearchBar(element)
element.focus();
}
}
//FILE SHIT
let oldfiles = {};
function handle_files(input, newfiles) {
if (!newfiles) return;
const ta = input.parentElement.parentElement.parentElement.parentElement.querySelector('textarea.file-ta');
if (oldfiles[ta.id]) {
let list = new DataTransfer();
for (const file of oldfiles[ta.id]) {
list.items.add(file);
}
for (const file of newfiles) {
list.items.add(file);
}
input.files = list.files;
}
else {
input.files = newfiles;
oldfiles[ta.id] = []
}
const span = input.previousElementSibling
if (input.files.length > 8)
{
alert("You can't upload more than 8 files at one time!")
input.value = null
input.parentElement.nextElementSibling.classList.add('d-none');
span.innerHTML = ''
oldfiles[ta.id] = []
return
}
if (!span.innerHTML) span.innerHTML = ' '
if (ta.value && !ta.value.endsWith('\n')) {
ta.value += '\n'
}
for (const file of newfiles) {
oldfiles[ta.id].push(file)
if (span.innerHTML != ' ') span.innerHTML += ', '
span.innerHTML += file.name.substr(0, 30);
if (location.pathname != '/chat')
ta.value += `[${file.name}]\n`;
}
autoExpand(ta)
ta.focus()
ta.selectionStart = ta.selectionEnd = ta.value.length;
input.parentElement.nextElementSibling.classList.remove('d-none')
if (typeof checkForRequired === "function") checkForRequired();
}
document.onpaste = function(event) {
const files = structuredClone(event.clipboardData.files);
if (!files.length) return
const focused = document.activeElement;
let input;
if (location.pathname.endsWith('/submit')) {
if (focused) {
input = document.getElementById('file-upload-submit')
}
else {
f=document.getElementById('file-upload');
f.files += files;
if (f.files.length > 8)
{
alert("You can't upload more than 8 files at one time!")
return
}
document.getElementById('filename-show').textContent = filename;
document.getElementById('urlblock').classList.add('d-none');
if (IMAGE_FORMATS.some(s => filename.endsWith(s)))
{
const fileReader = new FileReader();
fileReader.readAsDataURL(f.files[0]);
fileReader.addEventListener("load", function () {document.getElementById('image-preview').setAttribute('src', this.result);});
}
document.getElementById('post-url').value = null;
localStorage.setItem("post-url", "")
document.getElementById('image-upload-block').classList.remove('d-none')
checkForRequired();
return;
}
}
else if (focused) {
input = focused.parentElement.querySelector('input[type="file"]')
}
else {
input = document.querySelector('input[type="file"]')
}
handle_files(input, files);
}
function cancel_files(element) {
const input = element.previousElementSibling.querySelector('input[type="file"]');
const span = input.previousElementSibling;
const ta = input.parentElement.parentElement.parentElement.parentElement.querySelector('textarea.file-ta');
for (const file of input.files) {
ta.value = ta.value.replaceAll(`[${file.name}]`, "");
}
ta.value = ta.value.trim();
span.innerHTML = '';
input.value = null;
input.parentElement.nextElementSibling.classList.add('d-none');
oldfiles[ta.id] = [];
element.classList.add('d-none');
ta.focus();
if (typeof checkForRequired === "function") checkForRequired();
}

View File

@ -99,20 +99,6 @@ function updatebgselection(){
}
updatebgselection();
document.onpaste = function(event) {
const focused = document.activeElement;
if (focused.id == 'profile-bio-text') {
const files = structuredClone(event.clipboardData.files);
if (files.length)
{
f=document.getElementById('file-upload');
f.files = files;
changename('filename-show', f.id, focused.id)
}
}
}
const sr_toggle = document.getElementById("slurreplacer");
const sr_link = document.getElementById('slurreplacer-perma-link');
const pr_toggle = document.getElementById("profanityreplacer");

View File

@ -63,42 +63,6 @@ function hide_image() {
}
}
document.onpaste = function(event) {
files = structuredClone(event.clipboardData.files);
if (files.length > 8)
{
alert("You can't upload more than 8 files at one time!")
return
}
filename = files[0]
if (filename)
{
filename = filename.name.toLowerCase()
if (document.activeElement.id == 'post-text') {
document.getElementById('file-upload-submit').files = files;
changename('filename-show-submit', 'file-upload-submit', 'post-text')
}
else {
f=document.getElementById('file-upload');
f.files = files;
document.getElementById('filename-show').textContent = filename;
document.getElementById('urlblock').classList.add('d-none');
if (IMAGE_FORMATS.some(s => filename.endsWith(s)))
{
const fileReader = new FileReader();
fileReader.readAsDataURL(f.files[0]);
fileReader.addEventListener("load", function () {document.getElementById('image-preview').setAttribute('src', this.result);});
}
document.getElementById('post-url').value = null;
localStorage.setItem("post-url", "")
document.getElementById('image-upload-block').classList.remove('d-none')
}
checkForRequired();
}
}
document.getElementById('file-upload').addEventListener('change', function(){
const f = document.getElementById('file-upload');

View File

@ -82,8 +82,15 @@ function sendMessage(form) {
document.getElementById('message-preview-mobile').classList.add('d-none');
sendFormXHR(form,
() => {
document.getElementById('input-message').value = ''
document.getElementById('input-message-mobile').value = ''
for (const substr of ['', '-mobile']) {
const ta = document.getElementById(`input-message${substr}`);
ta.value = '';
const input = ta.parentElement.querySelector('input[type="file"]');
input.previousElementSibling.innerHTML = '';
input.value = null;
input.parentElement.nextElementSibling.classList.add('d-none');
oldfiles[ta.id] = [];
}
}
)
}

View File

@ -32,19 +32,20 @@ def process_files(files, v, body):
if files:
media_ratelimit(v)
while body.count('[file]') < len(files):
body += '\n[file]'
for file in files:
if f'[{file.filename}]' not in body:
body += f'\n[{file.filename}]'
if file.content_type.startswith('image/'):
name = f'/images/{time.time()}'.replace('.','') + '.webp'
file.save(name)
url = process_image(name, v)
body = body.replace('[file]', f"![]({url})", 1)
body = body.replace(f'[{file.filename}]', f"![]({url})", 1)
elif file.content_type.startswith('video/'):
body = body.replace('[file]', f"{SITE_FULL}{process_video(file, v)}", 1)
body = body.replace(f'[{file.filename}]', f"{SITE_FULL}{process_video(file, v)}", 1)
elif file.content_type.startswith('audio/'):
body = body.replace('[file]', f"{SITE_FULL}{process_audio(file, v)}", 1)
body = body.replace(f'[{file.filename}]', f"{SITE_FULL}{process_audio(file, v)}", 1)
else:
abort(415)
return body
@ -237,10 +238,11 @@ def process_dm_images(v, user, body):
files = request.files.getlist('file')[:8]
while body.count('[file]') < len(files):
body += '\n[file]'
for file in files:
if f'[{file.filename}]' not in body:
body += f'\n[{file.filename}]'
if file.content_type.startswith('image/'):
filename = f'/dm_images/{time.time()}'.replace('.','') + '.webp'
file.save(filename)
@ -268,7 +270,7 @@ def process_dm_images(v, user, body):
try: url = req['files'][0]['url']
except: abort(400, req['description'])
body = body.replace('[file]', url, 1)
body = body.replace(f'[{file.filename}]', url, 1)
with open(f"{LOG_DIRECTORY}/dm_images.log", "a+", encoding="utf-8") as f:
if user:

View File

@ -155,13 +155,14 @@ def comment(v:User):
if request.files.get("file") and not g.is_tor:
files = request.files.getlist('file')[:8]
while body.count('[file]') < len(files):
body += '\n[file]'
if files:
media_ratelimit(v)
for file in files:
if f'[{file.filename}]' not in body:
body += f'\n[{file.filename}]'
if file.content_type.startswith('image/'):
oldname = f'/images/{time.time()}'.replace('.','') + '.webp'
file.save(oldname)
@ -204,11 +205,11 @@ def comment(v:User):
purge_files_in_cache(f"https://{SITE}/assets/images/badges/{badge.id}.webp")
except Exception as e:
abort(400, str(e))
body = body.replace('[file]', f"![]({image})", 1)
body = body.replace(f'[{file.filename}]', f"![]({image})", 1)
elif file.content_type.startswith('video/'):
body = body.replace('[file]', f"{SITE_FULL}{process_video(file, v)}", 1)
body = body.replace(f'[{file.filename}]', f"{SITE_FULL}{process_video(file, v)}", 1)
elif file.content_type.startswith('audio/'):
body = body.replace('[file]', f"{SITE_FULL}{process_audio(file, v)}", 1)
body = body.replace(f'[{file.filename}]', f"{SITE_FULL}{process_audio(file, v)}", 1)
else:
abort(415)

View File

@ -116,11 +116,12 @@
<span class="my-auto ml-1">
<label class="btn btn-secondary format mb-0">
<div id="filename" class="mr-3" style="font-size:12px"><i class="fas fa-image" style="font-size:1.3rem!important"></i></div>
<input autocomplete="off" id="file" accept="image/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename','file','input-text')" hidden>
<input autocomplete="off" id="file" accept="image/*" type="file" name="file" {% if g.is_tor %}disabled{% endif %} hidden>
</label>
<button type="button" class="text-danger text-lg font-weight-bold ml-2 remove-files d-none" data-bs-toggle="tooltip" title="Remove Files">X</button>
</span>
<textarea id="input-text" minlength="1" maxlength="{% if SITE == 'rdrama.net' %}200{% else %}1000{% endif %}" {% if g.browser == "apple" %}style="font-size:16px!important"{% endif %} class="form-control" placeholder="Message" autocomplete="off" autofocus rows="1"></textarea>
<textarea id="input-text" minlength="1" maxlength="{% if SITE == 'rdrama.net' %}200{% else %}1000{% endif %}" {% if g.browser == "apple" %}style="font-size:16px!important"{% endif %} class="file-ta form-control" placeholder="Message" autocomplete="off" autofocus rows="1"></textarea>
<i id="chatsend" data-nonce="{{g.nonce}}" data-onclick="send()" class="btn btn-secondary fas fa-reply ml-3 my-auto" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" style="transform:rotateY(180deg);font-size:1.3rem!important"></i>
</div>

View File

@ -260,20 +260,16 @@
<div id="comment-edit-{{c.id}}" class="d-none comment-write collapsed child">
<input hidden name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}10000{% endif %}" data-preview="preview-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('comment-edit-body-{{c.id}}','charcount-edit-{{c.id}}')" id="comment-edit-body-{{c.id}}" data-id="{{c.id}}" name="body" form="comment-edit-form-{{c.id}}" class="comment-box form-control rounded" placeholder="Add your comment..." rows="3">{{c.body}}</textarea>
<textarea autocomplete="off" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}10000{% endif %}" data-preview="preview-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('comment-edit-body-{{c.id}}','charcount-edit-{{c.id}}')" id="comment-edit-body-{{c.id}}" data-id="{{c.id}}" name="body" form="comment-edit-form-{{c.id}}" class="file-ta comment-box form-control rounded" placeholder="Add your comment..." rows="3">{{c.body}}</textarea>
<div class="text-small font-weight-bold mt-1" id="charcount-edit-{{c.id}}" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div>
<div class="comment-format">
<small class="btn btn-secondary format m-0" data-nonce="{{g.nonce}}" data-onclick="getGifs('comment-edit-body-{{c.id}}')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF"><span class="font-weight-bolder text-uppercase">GIF</span></small>
&nbsp;
<small class="btn btn-secondary format m-0" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('comment-edit-body-{{c.id}}')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></small>
&nbsp;
<label class="btn btn-secondary format m-0" for="file-edit-reply-{{c.id}}">
<div id="filename-edit-reply-{{c.id}}"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-edit-reply-{{c.id}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-edit-reply-{{c.id}}','file-edit-reply-{{c.id}}','comment-edit-body-{{c.id}}')" hidden>
</label>
<small class="btn btn-secondary format m-0 ml-2" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('comment-edit-body-{{c.id}}')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></small>
{{macros.file_input('file-edit-reply-' ~ c.id, False)}}
</div>
<a class="text-small mt-3 d-inline-block" href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a>
<button type="button" id="edit-btn-{{c.id}}" form="comment-edit-form-{{c.id}}" class="btn btn-primary ml-2 fl-r commentmob" data-nonce="{{g.nonce}}" data-onclick="comment_edit('{{c.id}}');remove_dialog()">Save Edit</button>
@ -531,16 +527,13 @@
<div id="comment-form-space-{{c.id}}" class="comment-write collapsed child">
<div class="input-group">
<input hidden name="formkey" value="{{v|formkey}}">
<textarea data-fullname="{{c.fullname}}" required autocomplete="off" minlength="1" maxlength="10000" name="body" form="reply-to-c_{{c.id}}" data-id="{{c.id}}" class="comment-box form-control rounded" id="reply-form-body-{{c.id}}" rows="3" data-preview="message-reply-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this)"></textarea>
<textarea data-fullname="{{c.fullname}}" required autocomplete="off" minlength="1" maxlength="10000" name="body" form="reply-to-c_{{c.id}}" data-id="{{c.id}}" class="file-ta comment-box form-control rounded" id="reply-form-body-{{c.id}}" rows="3" data-preview="message-reply-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this)"></textarea>
<div class="comment-format" id="comment-format-bar-{{c.id}}">
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{c.id}}')" class="btn btn-secondary m-0 mt-3 mr-1" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{c.id}}')" class="btn btn-secondary format m-0" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
{% set upload_disabled = g.is_tor or not get_setting('dm_images') %}
<label class="btn btn-secondary m-0 mt-3 {% if upload_disabled %}disabled{% endif %}" for="file-upload-reply-{{c.fullname}}">
<div id="filename-show-reply-{{c.fullname}}"><i class="fas fa-image"></i></div>
<input autocomplete="off" id="file-upload-reply-{{c.fullname}}" accept="image/*" type="file" name="file" multiple="multiple" {% if upload_disabled %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-reply-{{c.fullname}}','file-upload-reply-{{c.fullname}}','reply-form-body-{{c.id}}')" hidden>
</label>
{{macros.file_input('file-upload-reply-' ~ c.fullname, True)}}
</div>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="remove_dialog()" class="btn btn-link text-muted ml-auto" data-toggleelement="reply-message-{{c.fullname}}" data-toggleattr="d-none">Cancel</button>

View File

@ -10,21 +10,20 @@
<label for="input-message" class="mt-3">Your message</label>
<input hidden name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" maxlength="10000" id="input-message" form="contactform" name="message" class="form-control" required></textarea>
<label class="btn btn-secondary m-0 mt-3" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('input-message')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji">
<i class="fas fa-smile-beam"></i>
</label>
<label class="btn btn-secondary m-0 mt-3" for="file-upload">
<div id="filename"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload" accept="image/*, video/*, audio/*" type="file" name="file" multiple="multiple" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename','file-upload','input-message')" hidden>
</label>
<input type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" value="Submit" class="btn btn-primary mt-3">
<textarea autocomplete="off" maxlength="10000" id="input-message" form="contactform" name="message" class="file-ta form-control" required></textarea>
<div class="mt-1">
<label class="btn btn-secondary m-0 format" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('input-message')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji">
<i class="fas fa-smile-beam"></i>
</label>
{{macros.file_input('file-uplod', False)}}
<input style="float:right" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" value="Submit" class="btn btn-primary">
</div>
</form>
<p class="my-3">Warrant Canary has been moved to <a href="/search/posts/?q=%22Monthly%20Website%20Stats%20Post%22&sort=new&t=all">Monthly Website Stats Posts</a>.</p>
<script defer src="{{'js/contact.js' | asset}}"></script>
{% include "modals/emoji.html" %}
{% else %}
<h4>by email: {{EMAIL}}</h4>

View File

@ -1,3 +1,5 @@
{%- import 'util/macros.html' as macros with context -%}
{% macro toggle_section(title, id, name, flag, below_text, disabled) %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
@ -60,7 +62,7 @@
<input minlength={{minlength}} maxlength={{maxlength}} pattern="{{pattern}}" autocomplete="off" id="{{id}}-body" type="text" name="{{form_name}}" class="form-control" placeholder='{{placeholder_text}}' value="{% if contents %}{{contents}}{% endif %}" {% if disabled %}disabled{% endif %}>
<div class="d-flex mt-2">
{% if show_marseys %}
<div><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('{{id}}-body')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></div>
<div class="ml-2"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('{{id}}-body')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></div>
{% endif %}
<small class="ml-3">{{below_text}}</small>
<input autocomplete="off" class="btn btn-primary ml-auto" id="{{id}}-save" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" value="{{button_text}}" {% if disabled %}disabled{% endif %}>
@ -78,18 +80,15 @@
<div class="w-lg-100">
<form id="{{id}}-form" action="{{form_action}}" method="post" enctype="multipart/form-data">
<input hidden name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" id="{{id}}-text" class="form-control rounded" placeholder="{{placeholder_text}}" rows="3" name="{{form_name}}" form="{{id}}-form" maxlength="{{maxlength}}">{% if contents %}{{contents}}{% endif %}</textarea>
<textarea autocomplete="off" id="{{id}}-text" class="file-ta form-control rounded" placeholder="{{placeholder_text}}" rows="3" name="{{form_name}}" form="{{id}}-form" maxlength="{{maxlength}}">{% if contents %}{{contents}}{% endif %}</textarea>
{% if show_extras %}
<div class="d-flex mt-2">
<button style="line-height:1" type="button" class="btn btn-secondary format d-inline-block m-0 font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('{{id}}-text')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</button>
&nbsp;
<button type="button" class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('{{id}}-text')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></button>
&nbsp;
<button type="button" class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam ml-2" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('{{id}}-text')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></button>
{% if show_file_upload %}
<label style="padding:0.3rem" class="btn btn-secondary format d-inline-block m-0">
<div id="filename-show"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload" accept="image/*, video/*, audio/*" type="file" name="file" multiple="multiple" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show','file-upload','{{id}}-text')" hidden>
</label>
{{macros.file_input('file-upload', False)}}
{% endif %}
</div>
{% endif %}

View File

@ -168,18 +168,16 @@
<input hidden name="formkey" value="{{v|formkey}}">
<input hidden name="current_page" value="{{request.path}}">
<textarea id="post-edit-title" autocomplete="off" max-length="500" name="title" class="comment-box form-control rounded" required placeholder="title">{{p.title}}</textarea>
<textarea autocomplete="off" name="body" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}20000{% endif %}" data-preview="post-edit-{{p.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('post-edit-box-{{p.id}}','charcount-post-edit')" id="post-edit-box-{{p.id}}" form="post-edit-form-{{p.id}}" class="comment-box form-control rounded" placeholder="Add text to your post..." rows="10" data-id="{{p.id}}">{{p.body}}</textarea>
<textarea autocomplete="off" name="body" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}20000{% endif %}" data-preview="post-edit-{{p.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('post-edit-box-{{p.id}}','charcount-post-edit')" id="post-edit-box-{{p.id}}" form="post-edit-form-{{p.id}}" class="file-ta comment-box form-control rounded" placeholder="Add text to your post..." rows="10" data-id="{{p.id}}">{{p.body}}</textarea>
<div class="text-small font-weight-bold mt-1" id="charcount-post-edit" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div>
<div class="comment-format">
<button type="button" class="format btn btn-secondary"><span class="font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('post-edit-box-{{p.id}}')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></button>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-edit-box-{{p.id}}')" class="format btn btn-secondary" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<label class="format btn btn-secondary m-0 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-edit-{{p.id}}">
<div id="filename-show-edit-{{p.id}}"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload-edit-{{p.id}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-edit-{{p.id}}','file-upload-edit-{{p.id}}','post-edit-box-{{p.id}}')" hidden>
</label>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-edit-box-{{p.id}}')" class="format btn btn-secondary ml-2" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
{{macros.file_input('file-upload-edit-' ~ p.id, False)}}
<small class="format d-none"><i class="fas fa-link"></i></small>
</div>

View File

@ -31,7 +31,7 @@
</div>
<label class='mt-4' for="title">Post Title</label>
<input autocomplete="off" class="form-control allow-emojis" id="post-title" type="text" name="title" placeholder="Required" value="{{title}}" minlength="1" maxlength="500" required data-nonce="{{g.nonce}}" data-oninput="checkForRequired();savetext()">
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-title')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn-2" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-title')" class="btn btn-secondary format d-inline-block m-0 ml-2" id="emoji-reply-btn-2" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<div id="urlblock">
<label for="URL" class="mt-3">URL</label>
<input autocomplete="off" class="form-control" id="post-url" name="url" type="url" placeholder="Optional if you have text." value="{{request.values.get('url','')}}" required data-nonce="{{g.nonce}}" data-oninput="checkForRequired();hide_image();savetext();checkRepost();autoSuggestTitle()">
@ -50,7 +50,7 @@
</div>
</div>
<label for="body" class="mt-3">Text<i class="fas fa-info-circle text-gray-400 ml-1" data-bs-toggle="tooltip" data-bs-placement="top" title="Uses markdown. Limited to 20000 characters."></i></label>
<textarea form="submitform" id="post-text" class="form-control rounded" placeholder="Optional if you have a link or an image." rows="7" name="body" data-preview="preview" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('post-text','character-count-submit-text-form');checkForRequired();savetext()" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}20000{% endif %}" required></textarea>
<textarea form="submitform" id="post-text" class="file-ta form-control rounded" placeholder="Optional if you have a link or an image." rows="7" name="body" data-preview="preview" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('post-text','character-count-submit-text-form');checkForRequired();savetext()" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}20000{% endif %}" required></textarea>
<div class="ghostdiv" style="display:none;"></div>
<div class="text-small font-weight-bold mt-1" id="character-count-submit-text-form" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div>
<p></p>
@ -58,12 +58,11 @@
Toggle preview
</div>
<small class="btn btn-secondary format d-inline-block m-0"><span class="font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('post-text')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></small>
&nbsp;
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-text')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<label class="format btn btn-secondary m-0 ml-2 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-submit">
<div id="filename-show-submit"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload-submit" multiple="multiple" accept="image/*, video/*, audio/*" type="file" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-submit','file-upload-submit','post-text');checkForRequired()" hidden>
</label>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-text')" class="btn btn-secondary format d-inline-block m-0 ml-2" id="emoji-reply-btn" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
{{macros.file_input('file-upload-submit', False)}}
<div id="preview" class="preview my-3"></div>
<div class="form-text text-small mt-1 mb-3"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div>
<div class="custom-control custom-checkbox">

View File

@ -24,14 +24,14 @@
{% if v and v.id != u.id and v.admin_level >= PERMS['USER_MODERATION_TOOLS_VISIBLE'] %}
<div class="admintools-user-lower-{{deviceType}}">
{% if v.admin_level >= PERMS['USER_TITLE_CHANGE'] %}
<div class="body d-lg-flex border-bottom mb-2">
<div class="body d-lg-flex border-bottom mt-4 mb-2">
<div class="w-lg-100">
<form action="/admin/title_change/{{u.id}}" method="post" data-nonce="{{g.nonce}}" data-onsubmit="sendFormXHR(this)">
<input hidden name="formkey" value="{{v|formkey}}">
<input maxlength=100 autocomplete="off" id="customtitlebody-{{deviceType}}" type="text" name="title" class="form-control" placeholder='Enter a flair here' value="{% if u.customtitleplain %}{{u.customtitleplain}}{% endif %}">
<div class="d-flex mt-2">
<div class="format"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('customtitlebody-{{deviceType}}')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></div>
<div class="custom-control custom-checkbox ml-3">
<div class="d-flex">
<div class="format pl-0"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('customtitlebody-{{deviceType}}')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></div>
<div class="custom-control custom-checkbox ml-2 mt-1">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="locked-{{deviceType}}" name="locked" {% if u.flairchanged %}checked{% endif %}>
<label class="custom-control-label" for="locked-{{deviceType}}">locked</label>
</div>

View File

@ -153,19 +153,15 @@
</div>
<form class="d-none toggleable" id="message" action="/@{{u.username}}/message" data-nonce="{{g.nonce}}" data-onsubmit="sendMessage(this)">
<input hidden name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" id="input-message" form="message" name="message" rows="3" minlength="1" maxlength="10000" class="form-control b2 mt-1" data-preview="message-preview" data-nonce="{{g.nonce}}" data-oninput="markdown(this)"></textarea>
<textarea autocomplete="off" id="input-message" form="message" name="message" rows="3" minlength="1" maxlength="10000" class="file-ta form-control b2 mt-1" data-preview="message-preview" data-nonce="{{g.nonce}}" data-oninput="markdown(this)"></textarea>
<button type="button" class="btn btn-secondary format d-inline-block m-0 py-2 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('input-message')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></button>
{% set upload_disabled = g.is_tor or not get_setting('dm_images') %}
<label class="btn btn-secondary m-0 py-1 px-2 {% if upload_disabled %}disabled{% endif %}" for="file-upload">
<div id="filename"><i class="fas fa-image"></i></div>
<input autocomplete="off" id="file-upload" accept="image/*" type="file" name="file" multiple="multiple" {% if upload_disabled %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename','file-upload','input-message')" hidden>
</label>
{{macros.file_input('file-upload', True)}}
&nbsp;
<input type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()" value="Submit" class="btn btn-primary">
<input style="float:right" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()" value="Submit" class="btn btn-primary">
</form>
<div id="message-preview" class="preview mt-2"></div>
@ -461,18 +457,14 @@
</div>
{% if v and v.id != u.id %}
<form class="d-none toggleable" id='message-mobile' action="/@{{u.username}}/message" data-nonce="{{g.nonce}}" data-onsubmit="sendMessage(this)">
<form class="d-none toggleable text-left" id='message-mobile' action="/@{{u.username}}/message" data-nonce="{{g.nonce}}" data-onsubmit="sendMessage(this)">
<input class="mt-1" hidden name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" id="input-message-mobile" form="message-mobile" name="message" rows="3" minlength="1" maxlength="10000" class="form-control" data-preview="message-preview-mobile" data-nonce="{{g.nonce}}" data-oninput="markdown(this)" required></textarea>
<textarea autocomplete="off" id="input-message-mobile" form="message-mobile" name="message" rows="3" minlength="1" maxlength="10000" class="file-ta form-control" data-preview="message-preview-mobile" data-nonce="{{g.nonce}}" data-oninput="markdown(this)" required></textarea>
<button type="button" class="btn btn-secondary format d-inline-block m-0 py-2 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('input-message')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></button>
<label class="btn btn-secondary m-0 py-1 px-2 {% if upload_disabled %}disabled{% endif %}" for="file-upload-mobile">
<div id="filename-mobile"><i class="fas fa-image"></i></div>
<input autocomplete="off" id="file-upload-mobile" accept="image/*" type="file" name="file" multiple="multiple" {% if upload_disabled %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-mobile','file-upload-mobile','input-message')" hidden>
</label>
{{macros.file_input('file-upload-mobile', True)}}
&nbsp;
<input type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()" value="Submit" class="btn btn-primary">
<input style="float:right" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()" value="Submit" class="btn btn-primary">
</form>
<div id="message-preview-mobile" class="preview my-3"></div>

View File

@ -110,13 +110,22 @@
<span class="ml-2 d-inline-block">{{p.views}} thread views</span>
{% endmacro %}
{% macro file_input(id, image_only) %}
<label class="btn btn-secondary format m-0 ml-2" for="{{id}}">
<i class="fas fa-{% if image_only %}image{% else %}file{% endif %}"></i><span></span>
<input autocomplete="off" id="{{id}}" accept="image/*{% if not image_only %}, video/*, audio/*{% endif %}" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} hidden>
</label>
<button type="button" class="text-danger text-lg font-weight-bold ml-2 remove-files d-none" data-bs-toggle="tooltip" title="Remove Files">X</button>
{% endmacro %}
{% macro comment_reply_box(target_fullname, html_id, wrapper_css_classes="", subwrapper_css_classes="", hide="", allow_file_upload=true, enable_cancel_button=true) %}
<div class="comment-box-wrapper{% if wrapper_css_classes %} {{wrapper_css_classes}}{% endif %}" id="{{html_id}}">
{% if v %}
<div id="comment-form-space-{{target_fullname}}" class="comment-write {{subwrapper_css_classes}}">
<input hidden name="formkey" value="{{v|formkey}}">
<input hidden name="parent_fullname" value="{target_fullname}}">
<textarea required autocomplete="off" {% if not (p and p.id in ADMIGGER_THREADS) %}{% if v.longpost %}minlength="280"{% elif v.bird %}maxlength="140"{% endif %}{% endif %} minlength="1" maxlength="10000" data-preview="form-preview-{{target_fullname}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('reply-form-body-{{target_fullname}}','charcount-{{target_fullname}}')" id="reply-form-body-{{target_fullname}}" data-fullname="{{target_fullname}}" class="comment-box form-control rounded" name="body" form="reply-to-{{target_fullname}}" placeholder="Add your comment..." rows="3"></textarea>
<textarea required autocomplete="off" {% if not (p and p.id in ADMIGGER_THREADS) %}{% if v.longpost %}minlength="280"{% elif v.bird %}maxlength="140"{% endif %}{% endif %} minlength="1" maxlength="10000" data-preview="form-preview-{{target_fullname}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('reply-form-body-{{target_fullname}}','charcount-{{target_fullname}}')" id="reply-form-body-{{target_fullname}}" data-fullname="{{target_fullname}}" class="file-ta comment-box form-control rounded" name="body" form="reply-to-{{target_fullname}}" placeholder="Add your comment..." rows="3"></textarea>
<div class="text-small font-weight-bold mt-1" id="charcount-{{target_fullname}}" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div>
@ -124,14 +133,11 @@
<button type="button" class="btn btn-secondary format d-inline-block m-0" for="gif-reply-btn-{{target_fullname}}">
<span id="gif-reply-btn-{{target_fullname}}" class="font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('reply-form-body-{{target_fullname}}')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span>
</button>
&nbsp;
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{target_fullname}}')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn-{{target_fullname}}" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
&nbsp;
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{target_fullname}}')" class="btn btn-secondary format d-inline-block m-0 ml-2" id="emoji-reply-btn-{{target_fullname}}" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
{% if allow_file_upload %}
<label class="format btn btn-secondary m-0 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-reply-{{target_fullname}}">
<div id="filename-show-reply-{{target_fullname}}"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload-reply-{{target_fullname}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-reply-{{target_fullname}}','file-upload-reply-{{target_fullname}}','reply-form-body-{{target_fullname}}')" hidden>
</label>
{{file_input('file-upload-reply-' ~ target_fullname, False)}}
{% endif %}
</div>
<button type="button" id="save-reply-to-{{target_fullname}}" form="reply-to-{{target_fullname}}" class="btn btn-primary text-whitebtn ml-auto fl-r" data-nonce="{{g.nonce}}" data-onclick="post_comment('{{target_fullname}}', '{{hide}}');remove_dialog();">Comment</button>