Merge branch 'master' of github.com:fatchan/jschan

merge-requests/208/head
fatchan 4 years ago
commit d906fc335e
  1. 43
      gulp/res/css/style.css
  2. BIN
      gulp/res/img/video.png
  3. 102
      gulp/res/js/expand.js
  4. 70
      gulp/res/js/forms.js
  5. 20
      models/forms/actionhandler.js
  6. 20
      package-lock.json
  7. 1
      views/includes/postform.pug
  8. 1
      views/pages/managebanners.pug

@ -260,6 +260,47 @@ p {
margin: 5px; margin: 5px;
} }
.upload-list {
max-height: 75px;
overflow-x: hidden;
overflow-y: auto;
max-width: 100%;
scrollbar-width: none;
border: 1px solid var(--input-borders);
margin-top: 1px;
display: none;
}
.upload-list::-webkit-scrollbar {
display: none;
}
.upload-item {
display: flex;
align-items: center;
position: relative;
}
.upload-item p {
max-width: calc(100% - 85px);
max-height: 1.5em;
overflow: hidden;
text-overflow: ellipsis;
position: absolute;
margin-left: 60px;
}
.upload-item a {
height: 50px;
display: flex;
align-items: center;
}
.upload-thumb {
width: 50px;
height: 50px;
object-fit: contain;
}
.catalog { .catalog {
display:flex; display:flex;
align-items:flex-start; align-items:flex-start;
@ -299,6 +340,7 @@ p {
min-width: 220px; min-width: 220px;
flex-grow: 1; flex-grow: 1;
flex-direction: column; flex-direction: column;
min-height: 38px;
} }
.form-file { .form-file {
@ -635,6 +677,7 @@ video, img {
display: flex; display: flex;
image-orientation: from-image; image-orientation: from-image;
position:relative; position:relative;
flex-direction: column;
} }
.expanded { .expanded {

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

@ -47,68 +47,63 @@ window.addEventListener('DOMContentLoaded', (event) => {
if (!isCatalog) { //dont expand on catalog if (!isCatalog) { //dont expand on catalog
const thumbs = document.getElementsByClassName('post-file-src'); const thumbs = document.getElementsByClassName('post-file-src');
const toggle = function(thumb, exp, fn, src) { const toggle = function(thumb, expanded, filename, src) {
if (loopEnabled) { if (thumb.style.display === 'none') { //closing
exp.loop = true;
} else {
exp.loop = false;
}
exp.volume = volumeLevel/100;
const close = exp.previousSibling.innerText === 'Close' ? exp.previousSibling : null;
if (thumb.style.display === 'none') {
//closing
thumb.style.display = ''; thumb.style.display = '';
exp.style.display = 'none'; expanded.style.display = 'none';
fn.style.maxWidth = ''; filename.style.maxWidth = '';
if (close) { } else { //expanding
src.style.visibility = 'visible';
close.style.display = 'none';
exp.pause();
}
} else {
//expanding
thumb.style.display = 'none'; thumb.style.display = 'none';
exp.style.display = ''; expanded.style.display = '';
if (exp.offsetWidth >= fn.offsetWidth) { if (expanded.offsetWidth >= filename.offsetWidth) {
fn.style.maxWidth = exp.offsetWidth+'px'; filename.style.maxWidth = expanded.offsetWidth+'px';
} }
if (close) { }
//handle css thing for play icon on vid/audio
const close = thumb.nextSibling.innerText === 'Close' ? thumb.nextSibling : null;
if (close) {
expanded.loop = loopEnabled;
expanded.volume = volumeLevel/100;
if (src.style.visibility === 'hidden') {
src.style.visibility = 'visible';
close.style.display = 'none';
expanded.pause();
} else {
src.style.visibility = 'hidden'; src.style.visibility = 'hidden';
close.style.display = ''; close.style.display = '';
exp.play(); expanded.play();
} }
} }
} }
const expand = function(e) { const expand = function(e) {
const fileLink = this.firstChild; if (e.target.nodeName === 'VIDEO' || e.target.nodeName === 'AUDIO') {
const fileSrc = fileLink.href; e.stopPropagation();
const type = this.dataset.type; return;
}
if (this.dataset.attachment == 'true') { if (this.dataset.attachment == 'true') {
return; //attachments dont expand return;
} }
const thumbElement = fileLink.firstChild; e.preventDefault();
const fileAnchor = this.firstChild;
const fileHref = fileAnchor.href;
const type = this.dataset.type;
const thumbElement = fileAnchor.firstChild;
const fileName = this.previousSibling; const fileName = this.previousSibling;
const next = thumbElement.nextSibling;
const pfs = this.closest('.post-file-src'); const pfs = this.closest('.post-file-src');
let expandedElement; let expandedElement = type === 'image' ? thumbElement.nextSibling : fileAnchor.nextSibling;
if (next) {
if (next.innerText === 'Close') { if (expandedElement) {
expandedElement = next.nextSibling; toggle(thumbElement, expandedElement, fileName, pfs);
} else { } else if (thumbElement.style.opacity !== '0.5') {
expandedElement = next;
}
}
if (!expandedElement && thumbElement.style.opacity !== '0.5') {
let source; let source;
fileLink.style.minWidth = fileLink.offsetWidth+'px';
fileLink.style.minHeight = fileLink.offsetHeight+'px';
switch(type) { switch(type) {
case 'image': case 'image':
e.preventDefault(); e.preventDefault();
fileAnchor.style.minWidth = fileAnchor.offsetWidth+'px';
fileAnchor.style.minHeight = fileAnchor.offsetHeight+'px';
thumbElement.style.opacity = '0.5'; thumbElement.style.opacity = '0.5';
thumbElement.style.cursor = 'wait' thumbElement.style.cursor = 'wait'
// loading bar experiment
if (localStorage.getItem('imageloadingbars') == 'true') { if (localStorage.getItem('imageloadingbars') == 'true') {
const request = new XMLHttpRequest(); const request = new XMLHttpRequest();
request.onprogress = (e) => { request.onprogress = (e) => {
@ -123,7 +118,6 @@ window.addEventListener('DOMContentLoaded', (event) => {
} }
expandedElement = document.createElement('img'); expandedElement = document.createElement('img');
source = expandedElement; source = expandedElement;
//some jank here to try and recude any delay induced by xhr
const loaded = function(e) { const loaded = function(e) {
pfs.removeAttribute('data-loading'); pfs.removeAttribute('data-loading');
pfs.removeAttribute('style'); pfs.removeAttribute('style');
@ -131,24 +125,23 @@ window.addEventListener('DOMContentLoaded', (event) => {
source.src = window.URL.createObjectURL(blob); source.src = window.URL.createObjectURL(blob);
thumbElement.style.opacity = ''; thumbElement.style.opacity = '';
thumbElement.style.cursor = ''; thumbElement.style.cursor = '';
fileLink.appendChild(expandedElement); fileAnchor.appendChild(expandedElement);
toggle(thumbElement, expandedElement, fileName, pfs); toggle(thumbElement, expandedElement, fileName, pfs);
} }
request.onload = loaded; request.onload = loaded;
request.responseType = 'blob'; request.responseType = 'blob';
request.open('GET', fileSrc, true); request.open('GET', fileHref, true);
request.send(null); request.send(null);
} else { } else {
// loading bar experiment
expandedElement = document.createElement('img'); expandedElement = document.createElement('img');
source = expandedElement; source = expandedElement;
source.onload = function() { source.onload = function() {
thumbElement.style.opacity = ''; thumbElement.style.opacity = '';
thumbElement.style.cursor = ''; thumbElement.style.cursor = '';
fileLink.appendChild(expandedElement); fileAnchor.appendChild(expandedElement);
toggle(thumbElement, expandedElement, fileName, pfs); toggle(thumbElement, expandedElement, fileName, pfs);
} }
source.src = fileSrc; source.src = fileHref;
} }
break; break;
case 'video': case 'video':
@ -165,19 +158,16 @@ window.addEventListener('DOMContentLoaded', (event) => {
expandedElement.controls = 'true'; expandedElement.controls = 'true';
source = document.createElement('source'); source = document.createElement('source');
expandedElement.appendChild(source); expandedElement.appendChild(source);
fileLink.appendChild(expandedElement); expandedElement.style.minWidth = fileAnchor.offsetWidth+'px';
fileLink.insertBefore(close, expandedElement); expandedElement.style.minHeight = fileAnchor.offsetHeight+'px';
pfs.appendChild(expandedElement);
fileAnchor.appendChild(close);
toggle(thumbElement, expandedElement, fileName, pfs); toggle(thumbElement, expandedElement, fileName, pfs);
source.src = fileSrc; source.src = fileHref;
break; break;
deault: deault:
return; return;
} }
} else if (expandedElement) {
e.preventDefault();
toggle(thumbElement, expandedElement, fileName, pfs);
} else {
e.preventDefault();
} }
}; };

@ -62,6 +62,7 @@ class formHandler {
if (this.fileInput) { if (this.fileInput) {
this.fileRequired = this.fileInput.required; this.fileRequired = this.fileInput.required;
this.fileLabel = this.fileInput.previousSibling; this.fileLabel = this.fileInput.previousSibling;
this.fileUploadList = this.fileInput.nextSibling;
this.multipleFiles = this.fileLabel.parentNode.previousSibling.firstChild.textContent.endsWith('s'); this.multipleFiles = this.fileLabel.parentNode.previousSibling.firstChild.textContent.endsWith('s');
this.fileLabelText = this.fileLabel.childNodes[0]; this.fileLabelText = this.fileLabel.childNodes[0];
this.fileLabel.addEventListener('dragover', e => this.fileLabelDrag(e)); this.fileLabel.addEventListener('dragover', e => this.fileLabelDrag(e));
@ -69,10 +70,17 @@ class formHandler {
this.fileInput.addEventListener('change', e => this.fileInputChange(e)); this.fileInput.addEventListener('change', e => this.fileInputChange(e));
this.fileLabel.addEventListener('auxclick', e => this.fileLabelAuxclick(e)); this.fileLabel.addEventListener('auxclick', e => this.fileLabelAuxclick(e));
} }
this.messageBox.addEventListener('keydown', e => this.controlEnterSubmit(e));
form.addEventListener('paste', e => this.paste(e)); form.addEventListener('paste', e => this.paste(e));
form.addEventListener('submit', e => this.formSubmit(e)); form.addEventListener('submit', e => this.formSubmit(e));
} }
controlEnterSubmit(e) {
if (e.ctrlKey && e.key === 'Enter') {
this.formSubmit(e);
}
}
formSubmit(e) { formSubmit(e) {
let postData; let postData;
if (this.form.getAttribute('enctype') === 'multipart/form-data') { if (this.form.getAttribute('enctype') === 'multipart/form-data') {
@ -101,8 +109,8 @@ class formHandler {
xhr.onloadstart = () => { xhr.onloadstart = () => {
this.submit.value = '0%'; this.submit.value = '0%';
} }
xhr.upload.onprogress = (e) => { xhr.upload.onprogress = (ev) => {
const progress = Math.floor((e.loaded / e.total) * 100); const progress = Math.floor((ev.loaded / ev.total) * 100);
this.submit.value = `${progress}%`; this.submit.value = `${progress}%`;
} }
xhr.onload = () => { xhr.onload = () => {
@ -153,9 +161,9 @@ class formHandler {
this.updateMessageBox(); this.updateMessageBox();
this.files = []; this.files = [];
this.updateFilesText(); this.updateFilesText();
const captcha = this.form.querySelector('img'); const captcha = this.form.querySelector('.captcharefresh');
if (captcha) { if (captcha) {
captcha.dispatchEvent(new Event('dblclick')); captcha.dispatchEvent(new Event('click'));
} }
} else { } else {
if (xhr.status === 413) { if (xhr.status === 413) {
@ -176,8 +184,8 @@ class formHandler {
this.submit.value = this.originalSubmitText; this.submit.value = this.originalSubmitText;
} }
} }
xhr.onerror = (e) => { xhr.onerror = (err) => {
console.error(e); //why is this error fucking useless console.error(err); //why is this error fucking useless
doModal({ doModal({
'title': 'Error', 'title': 'Error',
'message': 'Something broke' 'message': 'Something broke'
@ -197,11 +205,17 @@ class formHandler {
this.messageBox && this.messageBox.dispatchEvent(new Event('input')); this.messageBox && this.messageBox.dispatchEvent(new Event('input'));
} }
//remove a single file, unused atm removeFile(fileElem, name, size) {
removeFile(index) { fileElem.remove();
const childNode = this.fileLabel.childNodes[index+1]; //+1 because first one is fileLabelText let fileIndex;
childNode.remove(); this.files.find((f, index) => {
files.splice(index, 1); if (f.name === name && f.size === size) {
fileIndex = index;
}
})
this.files.splice(fileIndex, 1);
this.updateFilesText();
console.log(this.files)
} }
addFile(file) { addFile(file) {
@ -209,6 +223,38 @@ class formHandler {
this.fileInput.removeAttribute('required'); this.fileInput.removeAttribute('required');
} }
this.files.push(file); this.files.push(file);
//add to upload list
const listElem = document.createElement('div');
listElem.classList.add('upload-item');
const thumb = document.createElement('img');
const name = document.createElement('p');
const remove = document.createElement('a');
name.textContent = file.name;
remove.textContent = 'X';
switch (file.type.split('/')[0]) {
case 'image':
thumb.src = URL.createObjectURL(file);
break;
case 'audio':
thumb.src = '/file/audio.png'
break;
case 'video':
thumb.src = '/file/video.png'
break;
default:
thumb.src = '/file/attachment.png'
break;
}
thumb.classList.add('upload-thumb');
remove.classList.add('close');
listElem.appendChild(thumb);
listElem.appendChild(name);
listElem.appendChild(remove);
remove.addEventListener('click', () => {
this.removeFile(listElem, file.name, file.size);
})
this.fileUploadList.appendChild(listElem);
this.fileUploadList.style.display = 'unset';
} }
//show number of files on new label //show number of files on new label
@ -217,6 +263,8 @@ class formHandler {
return; return;
} }
if (this.files && this.files.length === 0) { if (this.files && this.files.length === 0) {
this.fileUploadList.textContent = '';
this.fileUploadList.style.display = 'none';
this.fileLabelText.nodeValue = `Select/Drop/Paste file${this.multipleFiles ? 's' : ''}`; this.fileLabelText.nodeValue = `Select/Drop/Paste file${this.multipleFiles ? 's' : ''}`;
} else { } else {
this.fileLabelText.nodeValue = `${this.files.length} file${this.files.length > 1 ? 's' : ''} selected`; this.fileLabelText.nodeValue = `${this.files.length} file${this.files.length > 1 ? 's' : ''} selected`;

@ -18,11 +18,19 @@ const { Posts, Boards, Modlogs } = require(__dirname+'/../../db/')
, getAffectedBoards = require(__dirname+'/../../helpers/affectedboards.js') , getAffectedBoards = require(__dirname+'/../../helpers/affectedboards.js')
, buildQueue = require(__dirname+'/../../queue.js') , buildQueue = require(__dirname+'/../../queue.js')
, { postPasswordSecret } = require(__dirname+'/../../configs/main.js') , { postPasswordSecret } = require(__dirname+'/../../configs/main.js')
, threadRegex = /\/[a-z0-9]+\/(?:manage\/)?thread\/(\d+)\.html/i
, { createHash, timingSafeEqual } = require('crypto'); , { createHash, timingSafeEqual } = require('crypto');
module.exports = async (req, res, next) => { module.exports = async (req, res, next) => {
const redirect = req.headers.referer || `/${req.params.board ? req.params.board+'/manage/reports' : 'globalmanage/recents'}.html`; let redirect = req.headers.referer;
if (!redirect) {
if (!req.params.board) {
redirect = '/globalmanage/recent.html';
} else {
redirect = `/${req.params.board}/${req.path.endsWith('modactions') ? 'manage/reports' : 'index'}.html`;
}
}
//if user isnt staff, and they put an action that requires password, e.g. delete/spoiler, then filter posts to only matching password //if user isnt staff, and they put an action that requires password, e.g. delete/spoiler, then filter posts to only matching password
if (res.locals.permLevel >= 4 && res.locals.actions.numPasswords > 0) { if (res.locals.permLevel >= 4 && res.locals.actions.numPasswords > 0) {
@ -54,6 +62,16 @@ module.exports = async (req, res, next) => {
const deleting = req.body.delete || req.body.delete_ip_board || req.body.delete_ip_global || req.body.delete_ip_thread; const deleting = req.body.delete || req.body.delete_ip_board || req.body.delete_ip_global || req.body.delete_ip_thread;
let { boardThreadMap, beforePages, threadBoards } = await getAffectedBoards(res.locals.posts, deleting); let { boardThreadMap, beforePages, threadBoards } = await getAffectedBoards(res.locals.posts, deleting);
if (deleting
&& req.params.board
&& req.headers.referer
&& boardThreadMap[req.params.board]) {
const threadRefMatch = req.headers.referer.match(threadRegex);
if (threadRefMatch && boardThreadMap[req.params.board].directThreads.has(+threadRefMatch[1])) {
redirect = `/${req.params.board}/${req.path.endsWith('modactions') ? 'manage/' : ''}index.html`;
}
}
const messages = []; const messages = [];
const modlogActions = [] const modlogActions = []
const combinedQuery = {}; const combinedQuery = {};

20
package-lock.json generated

@ -1064,9 +1064,9 @@
} }
}, },
"bson": { "bson": {
"version": "1.1.3", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz",
"integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg==" "integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q=="
}, },
"buffer-equal": { "buffer-equal": {
"version": "1.0.0", "version": "1.0.0",
@ -4116,9 +4116,9 @@
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
}, },
"ioredis": { "ioredis": {
"version": "4.16.1", "version": "4.16.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.16.1.tgz", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.16.2.tgz",
"integrity": "sha512-g76Mm9dE7BLuewncu1MimGZw5gDDjDwjoRony/VoSxSJEKAhuYncDEwYKYjtHi2NWsTNIB6XXRjE64uVa/wpKQ==", "integrity": "sha512-hlRK9q9K8pWpYIxUh079dWUWECiGNdI7+/AR21pgeqIBXQzjVKFnz0wXvmhEQZV3Hvv4saQpvJww9SkjwvPXZA==",
"requires": { "requires": {
"cluster-key-slot": "^1.1.0", "cluster-key-slot": "^1.1.0",
"debug": "^4.1.1", "debug": "^4.1.1",
@ -4943,12 +4943,12 @@
} }
}, },
"mongodb": { "mongodb": {
"version": "3.5.5", "version": "3.5.6",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.5.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.6.tgz",
"integrity": "sha512-GCjDxR3UOltDq00Zcpzql6dQo1sVry60OXJY3TDmFc2SWFY6c8Gn1Ardidc5jDirvJrx2GC3knGOImKphbSL3A==", "integrity": "sha512-sh3q3GLDLT4QmoDLamxtAECwC3RGjq+oNuK1ENV8+tnipIavss6sMYt77hpygqlMOCt0Sla5cl7H4SKCVBCGEg==",
"requires": { "requires": {
"bl": "^2.2.0", "bl": "^2.2.0",
"bson": "^1.1.1", "bson": "^1.1.4",
"denque": "^1.4.1", "denque": "^1.4.1",
"require_optional": "^1.0.1", "require_optional": "^1.0.1",
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",

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

@ -26,6 +26,7 @@ block content
span.col span.col
include ../includes/filelabel.pug include ../includes/filelabel.pug
input#file(type='file', name='file' multiple required) input#file(type='file', name='file' multiple required)
.upload-list
input(type='submit', value='submit') input(type='submit', value='submit')
if board.banners.length > 0 if board.banners.length > 0
hr(size=1) hr(size=1)

Loading…
Cancel
Save