file upload form changes for clipboard/drag+drop, and make it work on the banners upload page

merge-requests/208/head
fatchan 5 years ago
parent 6ef6567370
commit a5e7349c28
  1. 15
      gulp/res/css/style.css
  2. 3
      gulp/res/js/hide.js
  3. 10
      gulp/res/js/post.js
  4. 111
      gulp/res/js/progress.js
  5. 1
      helpers/files/mimetypes.js
  6. 4
      models/forms/makepost.js
  7. 1
      views/includes/filelabel.pug
  8. 2
      views/includes/head.pug
  9. 4
      views/includes/postform.pug
  10. 4
      views/mixins/post.pug
  11. 4
      views/pages/managebanners.pug

@ -247,6 +247,15 @@ p {
background: black!important;
}
.filelabel {
cursor: pointer;
border-style: dashed !important;
justify-content: center;
padding: 5px;
min-width: 220px;
flex-grow: 1;
}
.banposts .thread {
display: none;
text-align: left;
@ -474,7 +483,7 @@ details.actions div {
/*margin-top: 10px;*/
}
.toggle {
.toggle, .togglable {
display: none;
}
@ -488,10 +497,6 @@ details.actions div {
max-width: 100%;
}
.togglable {
display: none;
}
.user-id {
text-shadow: #000 0px 0px 1px, #000 0px 0px 1px, #000 0px 0px 1px, #000 0px 0px 1px, #000 0px 0px 1px, #000 0px 0px 1px;
color: white;

@ -1,3 +1,6 @@
const fileInput = document.getElementById('file');
fileInput ? fileInput.style.display = 'none' : void 0;
let hidden;
const loadHiddenStorage = () => {

@ -77,7 +77,10 @@ pug_html = pug_html + "\u003Cdiv class=\"post-files\"\u003E";
if ('number' == typeof $$obj.length) {
for (var pug_index0 = 0, $$l = $$obj.length; pug_index0 < $$l; pug_index0++) {
var file = $$obj[pug_index0];
pug_html = pug_html + ("\u003Cdiv class=\"post-file\"\u003E\u003Cspan class=\"post-file-info\"\u003E\u003Cspan\u003E\u003Ca" + (pug_attr("href", '/img/'+file.filename, true, false)+pug_attr("title", 'Download '+file.originalFilename, true, false)+pug_attr("download", file.originalFilename, true, false)) + "\u003E" + (pug_escape(null == (pug_interp = post.spoiler ? 'Spoiler File' : file.originalFilename) ? "" : pug_interp)) + "\u003C\u002Fa\u003E\u003C\u002Fspan\u003E\u003Cbr\u002F\u003E\u003Cspan\u003E (" + (pug_escape(null == (pug_interp = file.sizeString) ? "" : pug_interp)) + ", " + (pug_escape(null == (pug_interp = file.geometryString) ? "" : pug_interp)));
pug_html = pug_html + ("\u003Cdiv class=\"post-file\"\u003E\u003Cspan class=\"post-file-info\"\u003E\u003Cspan\u003E\u003Ca" + (pug_attr("href", '/img/'+file.filename, true, false)+pug_attr("title", 'Download '+file.originalFilename, true, false)+pug_attr("download", file.originalFilename, true, false)) + "\u003E" + (pug_escape(null == (pug_interp = post.spoiler ? 'Spoiler File' : file.originalFilename) ? "" : pug_interp)) + "\u003C\u002Fa\u003E\u003C\u002Fspan\u003E\u003Cbr\u002F\u003E\u003Cspan\u003E (" + (pug_escape(null == (pug_interp = file.sizeString) ? "" : pug_interp)));
if (file.geometryString) {
pug_html = pug_html + (", " + (pug_escape(null == (pug_interp = file.geometryString) ? "" : pug_interp)));
}
if (file.durationString) {
pug_html = pug_html + (", " + (pug_escape(null == (pug_interp = file.durationString) ? "" : pug_interp)));
}
@ -105,7 +108,10 @@ pug_html = pug_html + "\u003C\u002Fa\u003E\u003C\u002Fdiv\u003E\u003C\u002Fdiv\u
for (var pug_index0 in $$obj) {
$$l++;
var file = $$obj[pug_index0];
pug_html = pug_html + ("\u003Cdiv class=\"post-file\"\u003E\u003Cspan class=\"post-file-info\"\u003E\u003Cspan\u003E\u003Ca" + (pug_attr("href", '/img/'+file.filename, true, false)+pug_attr("title", 'Download '+file.originalFilename, true, false)+pug_attr("download", file.originalFilename, true, false)) + "\u003E" + (pug_escape(null == (pug_interp = post.spoiler ? 'Spoiler File' : file.originalFilename) ? "" : pug_interp)) + "\u003C\u002Fa\u003E\u003C\u002Fspan\u003E\u003Cbr\u002F\u003E\u003Cspan\u003E (" + (pug_escape(null == (pug_interp = file.sizeString) ? "" : pug_interp)) + ", " + (pug_escape(null == (pug_interp = file.geometryString) ? "" : pug_interp)));
pug_html = pug_html + ("\u003Cdiv class=\"post-file\"\u003E\u003Cspan class=\"post-file-info\"\u003E\u003Cspan\u003E\u003Ca" + (pug_attr("href", '/img/'+file.filename, true, false)+pug_attr("title", 'Download '+file.originalFilename, true, false)+pug_attr("download", file.originalFilename, true, false)) + "\u003E" + (pug_escape(null == (pug_interp = post.spoiler ? 'Spoiler File' : file.originalFilename) ? "" : pug_interp)) + "\u003C\u002Fa\u003E\u003C\u002Fspan\u003E\u003Cbr\u002F\u003E\u003Cspan\u003E (" + (pug_escape(null == (pug_interp = file.sizeString) ? "" : pug_interp)));
if (file.geometryString) {
pug_html = pug_html + (", " + (pug_escape(null == (pug_interp = file.geometryString) ? "" : pug_interp)));
}
if (file.durationString) {
pug_html = pug_html + (", " + (pug_escape(null == (pug_interp = file.durationString) ? "" : pug_interp)));
}

@ -12,17 +12,49 @@ const doModal = (data) => {
window.addEventListener('DOMContentLoaded', () => {
const isThread = /\/\w+\/thread\/\d+.html/.test(window.location.pathname);
const isBanners = window.location.pathname.endsWith('banners.html');
const form = document.getElementById('postform');
const fileInput = form.querySelector('input[type="file"]');
const submit = document.getElementById('submitpost');
const form = isBanners ? document.querySelector('form') : document.getElementById('postform');
const submit = form ? form.querySelector('input[type="submit"]') : null;
if (!submit || !form) {
return; //no postform on this page
return;
}
const messageBox = document.getElementById('message');
messageBox.addEventListener('paste', (e) => {
const fileInput = document.getElementById('file');
const fileLabel = fileInput.previousSibling;
let files = [];
const removeFile = (name) => {
for(let i = 1; i < fileLabel.childNodes.length; i++) {
const childNode = fileLabel.childNodes[i];
if (childNode.nodeValue === name) {
childNode.nextSibling.remove();
childNode.remove();
files = files.filter(file => file.name !== name);
}
}
}
//show number of files on new label
const updateFilesText = () => {
if (files.length === 0) {
fileLabel.innerText = 'Upload/Drop/Paste file(s)';
} else {
fileLabel.innerText = `${files.length} files selected`;
//todo make x marks to remove each one with "removeFile"
}
}
//remove files
const clearFiles = () => {
files = []; //empty file list
fileInput.value = null; //remove the files for real
updateFilesText();
}
//handle paste image from clipboard
document.addEventListener('paste', (e) => {
const clipboard = e.clipboardData;
if (clipboard.items && clipboard.items.length > 0) {
const items = clipboard.items;
@ -30,32 +62,81 @@ window.addEventListener('DOMContentLoaded', () => {
const item = items[i];
if (item.kind === 'file') {
const file = new File([item.getAsFile()], 'ClipboardImage.png', { type: item.type });
const upload = new DataTransfer();
upload.items.add(file);
fileInput.files = upload.files;
//TODO: make this support multiple files somehow, not sure
files.push(file);
updateFilesText();
}
}
}
});
//handle drag+drop files
fileLabel.ondragover = (e) => {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}
fileLabel.ondrop = (e) => {
e.stopPropagation();
e.preventDefault();
const newFiles = e.dataTransfer.files;
for (let i = 0; i < newFiles.length; i++) {
files.push(newFiles[i]);
}
updateFilesText();
}
//add files to list instead of replacing when regular upload
fileInput.onchange = () => {
fileLabel.innerText = `${fileInput.files.length} files selected`;
const newFiles = fileInput.files;
for (let i = 0; i < newFiles.length; i++) {
files.push(newFiles[i]);
}
updateFilesText();
}
//middle click to clear files
fileLabel.onauxclick = (e) => {
if (e.button !== 1) { //middle click only
return;
}
clearFiles();
}
form.addEventListener('submit', function(event) {
if (localStorage.getItem('live') != 'true') {
if (files && files.length > 0) {
//add files to file input element
const filesToUpload = new DataTransfer();
for (let i = 0; i < files.length; i++) {
filesToUpload.items.add(files[i]);
}
fileInput.files = filesToUpload.files;
//TODO: switch this line to workaround https://stackoverflow.com/a/46780880 - http://archive.is/niUVU
}
if (isBanners || localStorage.getItem('live') != 'true') {
return true;
}
event.preventDefault();
submit.disabled = true;
submit.disabled = true; //prevent clicking post more than once
const xhr = new XMLHttpRequest();
xhr.onloadstart = function() {
submit.value = '0%';
}
xhr.upload.onprogress = function(e) {
const progress = Math.floor((e.loaded / e.total) * 100);
submit.value = `${progress}%`;
}
xhr.onload = function() {
submit.value = 'New Reply';
}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
submit.disabled = false;
@ -71,11 +152,14 @@ window.addEventListener('DOMContentLoaded', () => {
//successful post
if (!isThread && xhr.responseURL) {
window.location = xhr.responseURL;
return;
} else if (socket && socket.connected && json) {
window.myPostId = json.postId;
window.location.hash = json.postId;
}
form.reset(); //reset form on success
files = [];
updateFilesText();
const captcha = form.getElementsByTagName('img');
if (captcha.length > 0) {
captcha[0].dispatchEvent(new Event('dblclick'));
@ -95,6 +179,7 @@ window.addEventListener('DOMContentLoaded', () => {
submit.value = 'New Reply';
}
}
xhr.onerror = function() {
doModal({
'title': 'Error',
@ -102,9 +187,11 @@ window.addEventListener('DOMContentLoaded', () => {
});
submit.disabled = false;
}
xhr.open(form.getAttribute('method'), form.getAttribute('action'), true);
xhr.setRequestHeader('x-using-xhr', true);
xhr.send(new FormData(form));
});
window.addEventListener('addPost', function(e) {

@ -22,6 +22,7 @@ const videoMimeTypes = new Set([
]);
const audioMimeTypes = new Set([
'audio/mp3',
'audio/mpeg',
'audio/ogg',
'audio/wav',

@ -201,7 +201,7 @@ module.exports = async (req, res, next) => {
});
}
processedFile.duration = videoData.format.duration;
processedFile.durationString = new Date(videoData.format.duration*1000).toLocaleString('en-US', {hour12:false}).split(' ')[1].replace(/^00:/, '');//breaks for over 24h video
processedFile.durationString = new Date(videoData.format.duration*1000).toISOString().substr(11,8).replace(/^00:/, '');//breaks for over 24h video
processedFile.geometry = {width: videoData.streams[0].coded_width, height: videoData.streams[0].coded_height} // object with width and height pixels
processedFile.sizeString = formatSize(processedFile.size) // 123 Ki string
processedFile.geometryString = `${processedFile.geometry.width}x${processedFile.geometry.height}` // 123 x 123 string
@ -217,7 +217,7 @@ module.exports = async (req, res, next) => {
case 'audio': {
const audioData = await ffprobe(req.files.file[i].tempFilePath, null, true);
processedFile.duration = audioData.format.duration;
processedFile.durationString = new Date(audioData.format.duration*1000).toLocaleString('en-US', {hour12:false}).split(' ')[1].replace(/^00:/, '');//breaks for over 24h video
processedFile.durationString = new Date(audioData.format.duration*1000).toISOString().substr(11,8).replace(/^00:/, '');//breaks for over 24h video
processedFile.sizeString = formatSize(processedFile.size) // 123 Ki string
processedFile.hasThumb = false;
if (!existsFull) {

@ -0,0 +1 @@
label.jsonly.postform-style.filelabel(for='file') Upload/Drop/Paste file(s)

@ -1,7 +1,7 @@
meta(charset='utf-8')
meta(name='viewport', content='width=device-width, initial-scale=1')
noscript
style .jsonly { display: none; }
style .jsonly { display: none!important; }
link(rel='stylesheet' href='/css/style.css')
- const isBoard = board != null;
- const theme = isBoard ? board.settings.theme : defaultTheme;

@ -40,7 +40,9 @@ section.form-wrapper.flex-center
.label Files
if fileRequired
.required *
input(type='file', name='file' multiple required=fileRequired)
span.col
include ./filelabel.pug
input#file(type='file', name='file' multiple required=fileRequired )
if board.settings.userPostSpoiler
label.postform-style.ph-5.ml-1
input(type='checkbox', name='spoiler', value='true')

@ -57,7 +57,9 @@ mixin post(post, truncate, manage=false, globalmanage=false, ban=false)
span: a(href='/img/'+file.filename title='Download '+file.originalFilename download=file.originalFilename) #{post.spoiler ? 'Spoiler File' : file.originalFilename}
br
span
| (#{file.sizeString}, #{file.geometryString}
| (#{file.sizeString}
if file.geometryString
| , #{file.geometryString}
if file.durationString
| , #{file.durationString}
| )

@ -18,7 +18,9 @@ block content
.row
.label Upload
.required *
input#file(type='file', name='file' multiple required)
span.col
include ../includes/filelabel.pug
input#file(type='file', name='file' multiple required)
input(type='submit', value='submit')
if board.banners.length > 0
hr(size=1)

Loading…
Cancel
Save