From 5b71b0a81a4379045f7df7c464a9ef6c2ba50db7 Mon Sep 17 00:00:00 2001 From: Aevann Date: Mon, 27 Feb 2023 17:02:35 +0200 Subject: [PATCH] refactor file upload --- files/assets/js/bottom.js | 10 ++ files/assets/js/chat.js | 23 +--- files/assets/js/comments_v.js | 90 +++++------- files/assets/js/contact.js | 9 -- files/assets/js/core.js | 166 +++++++++++++++++++---- files/assets/js/settings_profile.js | 14 -- files/assets/js/submit.js | 36 ----- files/assets/js/userpage_v.js | 11 +- files/helpers/media.py | 18 +-- files/routes/comments.py | 11 +- files/templates/chat.html | 5 +- files/templates/comments.html | 21 +-- files/templates/contact.html | 21 ++- files/templates/settings/common.html | 17 ++- files/templates/submission.html | 10 +- files/templates/submit.html | 15 +- files/templates/userpage/admintools.html | 8 +- files/templates/userpage/banner.html | 22 +-- files/templates/util/macros.html | 22 +-- 19 files changed, 276 insertions(+), 253 deletions(-) delete mode 100644 files/assets/js/contact.js diff --git a/files/assets/js/bottom.js b/files/assets/js/bottom.js index 831957c85..6d2f54018 100644 --- a/files/assets/js/bottom.js +++ b/files/assets/js/bottom.js @@ -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); diff --git a/files/assets/js/chat.js b/files/assets/js/chat.js index 5a4925294..b55621f51 100644 --- a/files/assets/js/chat.js +++ b/files/assets/js/chat.js @@ -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 = '' - 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) diff --git a/files/assets/js/comments_v.js b/files/assets/js/comments_v.js index 814b2be25..a61c7c005 100644 --- a/files/assets/js/comments_v.js +++ b/files/assets/js/comments_v.js @@ -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 = ''; - } + + 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 = ''; 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 = ''; - 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) diff --git a/files/assets/js/contact.js b/files/assets/js/contact.js deleted file mode 100644 index bc6ad51d6..000000000 --- a/files/assets/js/contact.js +++ /dev/null @@ -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') -} diff --git a/files/assets/js/core.js b/files/assets/js/core.js index 8725f431d..00096ff08 100644 --- a/files/assets/js/core.js +++ b/files/assets/js/core.js @@ -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, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); } -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(); +} diff --git a/files/assets/js/settings_profile.js b/files/assets/js/settings_profile.js index 40bef5df0..8017f1a79 100644 --- a/files/assets/js/settings_profile.js +++ b/files/assets/js/settings_profile.js @@ -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"); diff --git a/files/assets/js/submit.js b/files/assets/js/submit.js index ce036380a..d0203ea01 100644 --- a/files/assets/js/submit.js +++ b/files/assets/js/submit.js @@ -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'); diff --git a/files/assets/js/userpage_v.js b/files/assets/js/userpage_v.js index 87f921b65..b7f78f684 100644 --- a/files/assets/js/userpage_v.js +++ b/files/assets/js/userpage_v.js @@ -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] = []; + } } ) } diff --git a/files/helpers/media.py b/files/helpers/media.py index 7bbfc8bb0..5df9bb2fb 100644 --- a/files/helpers/media.py +++ b/files/helpers/media.py @@ -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: diff --git a/files/routes/comments.py b/files/routes/comments.py index 2933be7ac..ab64eca1d 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -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) diff --git a/files/templates/chat.html b/files/templates/chat.html index 5c601ea69..e911c9966 100644 --- a/files/templates/chat.html +++ b/files/templates/chat.html @@ -116,11 +116,12 @@ + - + diff --git a/files/templates/comments.html b/files/templates/comments.html index f7ca45253..de03797a3 100644 --- a/files/templates/comments.html +++ b/files/templates/comments.html @@ -260,20 +260,16 @@