mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-16 02:36:16 +01:00
feat: add upload helper module for drag&drop, paste, closes #6388
fix chat input not getting focused
This commit is contained in:
@@ -173,3 +173,12 @@
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.imagedrop {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
color: @gray-light;
|
||||
width: 100%;
|
||||
display: none;
|
||||
}
|
||||
@@ -14,11 +14,12 @@ define('forum/chats', [
|
||||
'alerts',
|
||||
'chat',
|
||||
'api',
|
||||
'uploadHelpers',
|
||||
], function (
|
||||
components, translator, mousetrap,
|
||||
recentChats, search, messages,
|
||||
autocomplete, hooks, bootbox, alerts, chatModule,
|
||||
api
|
||||
api, uploadHelpers
|
||||
) {
|
||||
const Chats = {
|
||||
initialised: false,
|
||||
@@ -69,12 +70,35 @@ define('forum/chats', [
|
||||
Chats.addCharactersLeftHandler($('[component="chat/main-wrapper"]'));
|
||||
Chats.addIPHandler($('[component="chat/main-wrapper"]'));
|
||||
Chats.createAutoComplete($('[component="chat/input"]'));
|
||||
Chats.addUploadHandler({
|
||||
dragDropAreaEl: $('.chats-full'),
|
||||
pasteEl: $('[component="chat/input"]'),
|
||||
uploadFormEl: $('[component="chat/upload"]'),
|
||||
inputEl: $('[component="chat/input"]'),
|
||||
});
|
||||
|
||||
$('[data-action="close"]').on('click', function () {
|
||||
Chats.switchChat();
|
||||
});
|
||||
};
|
||||
|
||||
Chats.addUploadHandler = function (options) {
|
||||
uploadHelpers.init({
|
||||
dragDropAreaEl: options.dragDropAreaEl,
|
||||
pasteEl: options.pasteEl,
|
||||
uploadFormEl: options.uploadFormEl,
|
||||
route: '/api/post/upload', // using same route as post uploads
|
||||
callback: function (uploads) {
|
||||
const inputEl = options.inputEl;
|
||||
let text = inputEl.val();
|
||||
uploads.forEach((upload) => {
|
||||
text = text + (text ? '\n' : '') + (upload.isImage ? '!' : '') + `[${upload.filename}](${upload.url})`;
|
||||
});
|
||||
inputEl.val(text);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Chats.addIPHandler = function (container) {
|
||||
container.on('click', '.chat-ip-button', function () {
|
||||
const ipEl = $(this).parent();
|
||||
|
||||
@@ -89,8 +89,8 @@ define('alerts', ['translator', 'components', 'hooks'], function (translator, co
|
||||
}
|
||||
|
||||
function updateAlert(alert, params) {
|
||||
alert.find('strong').html(params.title);
|
||||
alert.find('p').html(params.message);
|
||||
alert.find('strong').translateHtml(params.title);
|
||||
alert.find('p').translateHtml(params.message);
|
||||
alert.attr('class', 'alert alert-dismissable alert-' + params.type + ' clearfix');
|
||||
|
||||
clearTimeout(parseInt(alert.attr('timeoutId'), 10));
|
||||
@@ -98,12 +98,7 @@ define('alerts', ['translator', 'components', 'hooks'], function (translator, co
|
||||
startTimeout(alert, params);
|
||||
}
|
||||
|
||||
alert.children().fadeOut(100);
|
||||
translator.translate(alert.html(), function (translatedHTML) {
|
||||
alert.children().fadeIn(100);
|
||||
alert.html(translatedHTML);
|
||||
hooks.fire('action:alert.update', { alert, params });
|
||||
});
|
||||
|
||||
// Handle changes in the clickfn
|
||||
alert.off('click').removeClass('pointer');
|
||||
|
||||
@@ -196,7 +196,9 @@ define('chat', [
|
||||
|
||||
module.createModal = function (data, callback) {
|
||||
callback = callback || function () {};
|
||||
require(['scrollStop', 'forum/chats', 'forum/chats/messages'], function (scrollStop, Chats, ChatsMessages) {
|
||||
require([
|
||||
'scrollStop', 'forum/chats', 'forum/chats/messages',
|
||||
], function (scrollStop, Chats, ChatsMessages) {
|
||||
app.parseAndTranslate('chat', data, function (chatModal) {
|
||||
if (module.modalExists(data.roomId)) {
|
||||
return callback(module.getModal(data.roomId));
|
||||
@@ -233,7 +235,7 @@ define('chat', [
|
||||
taskbar.updateActive(uuid);
|
||||
},
|
||||
stop: function () {
|
||||
chatModal.find('#chat-message-input').focus();
|
||||
module.focusInput(chatModal);
|
||||
},
|
||||
distance: 10,
|
||||
handle: '.modal-header',
|
||||
@@ -297,6 +299,14 @@ define('chat', [
|
||||
|
||||
Chats.addCharactersLeftHandler(chatModal);
|
||||
Chats.addIPHandler(chatModal);
|
||||
|
||||
Chats.addUploadHandler({
|
||||
dragDropAreaEl: chatModal.find('.modal-content'),
|
||||
pasteEl: chatModal,
|
||||
uploadFormEl: chatModal.find('[component="chat/upload"]'),
|
||||
inputEl: chatModal.find('[component="chat/input"]'),
|
||||
});
|
||||
|
||||
ChatsMessages.addSocketListeners();
|
||||
|
||||
taskbar.push('chat', chatModal.attr('data-uuid'), {
|
||||
@@ -318,7 +328,9 @@ define('chat', [
|
||||
};
|
||||
|
||||
module.focusInput = function (chatModal) {
|
||||
setTimeout(function () {
|
||||
chatModal.find('[component="chat/input"]').focus();
|
||||
}, 20);
|
||||
};
|
||||
|
||||
module.close = function (chatModal) {
|
||||
|
||||
199
public/src/modules/uploadHelpers.js
Normal file
199
public/src/modules/uploadHelpers.js
Normal file
@@ -0,0 +1,199 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
define('uploadHelpers', ['alerts'], function (alerts) {
|
||||
const uploadHelpers = {};
|
||||
|
||||
uploadHelpers.init = function (options) {
|
||||
const formEl = options.uploadFormEl;
|
||||
if (!formEl.length) {
|
||||
return;
|
||||
}
|
||||
formEl.attr('action', config.relative_path + options.route);
|
||||
|
||||
if (options.dragDropAreaEl) {
|
||||
uploadHelpers.handleDragDrop({
|
||||
container: options.dragDropAreaEl,
|
||||
callback: function (upload) {
|
||||
uploadHelpers.ajaxSubmit({
|
||||
uploadForm: formEl,
|
||||
upload: upload,
|
||||
callback: options.callback,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (options.pasteEl) {
|
||||
uploadHelpers.handlePaste({
|
||||
container: options.pasteEl,
|
||||
callback: function (upload) {
|
||||
uploadHelpers.ajaxSubmit({
|
||||
uploadForm: formEl,
|
||||
upload: upload,
|
||||
callback: options.callback,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
uploadHelpers.handleDragDrop = function (options) {
|
||||
let draggingDocument = false;
|
||||
const postContainer = options.container;
|
||||
const drop = options.container.find('.imagedrop');
|
||||
|
||||
postContainer.on('dragenter', function onDragEnter() {
|
||||
if (draggingDocument) {
|
||||
return;
|
||||
}
|
||||
drop.css('top', '0px');
|
||||
drop.css('height', postContainer.height() + 'px');
|
||||
drop.css('line-height', postContainer.height() + 'px');
|
||||
drop.show();
|
||||
|
||||
drop.on('dragleave', function () {
|
||||
drop.hide();
|
||||
drop.off('dragleave');
|
||||
});
|
||||
});
|
||||
|
||||
drop.on('drop', function onDragDrop(e) {
|
||||
e.preventDefault();
|
||||
const files = e.originalEvent.dataTransfer.files;
|
||||
|
||||
if (files.length) {
|
||||
let formData;
|
||||
if (window.FormData) {
|
||||
formData = new FormData();
|
||||
for (var i = 0; i < files.length; ++i) {
|
||||
formData.append('files[]', files[i], files[i].name);
|
||||
}
|
||||
}
|
||||
options.callback({
|
||||
files: files,
|
||||
formData: formData,
|
||||
});
|
||||
}
|
||||
|
||||
drop.hide();
|
||||
return false;
|
||||
});
|
||||
|
||||
function cancel(e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
$(document)
|
||||
.off('dragstart')
|
||||
.on('dragstart', function () {
|
||||
draggingDocument = true;
|
||||
})
|
||||
.off('dragend')
|
||||
.on('dragend', function () {
|
||||
draggingDocument = false;
|
||||
});
|
||||
|
||||
drop.on('dragover', cancel);
|
||||
drop.on('dragenter', cancel);
|
||||
};
|
||||
|
||||
uploadHelpers.handlePaste = function (options) {
|
||||
const container = options.container;
|
||||
container.on('paste', function (event) {
|
||||
const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items;
|
||||
const files = [];
|
||||
const fileNames = [];
|
||||
let formData = null;
|
||||
if (window.FormData) {
|
||||
formData = new FormData();
|
||||
}
|
||||
[].forEach.call(items, function (item) {
|
||||
const file = item.getAsFile();
|
||||
if (file) {
|
||||
const fileName = utils.generateUUID() + '-' + file.name;
|
||||
if (formData) {
|
||||
formData.append('files[]', file, fileName);
|
||||
}
|
||||
files.push(file);
|
||||
fileNames.push(fileName);
|
||||
}
|
||||
});
|
||||
|
||||
if (files.length) {
|
||||
options.callback({
|
||||
files: files,
|
||||
fileNames: fileNames,
|
||||
formData: formData,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
uploadHelpers.ajaxSubmit = function (options) {
|
||||
const files = [...options.upload.files];
|
||||
|
||||
for (let i = 0; i < files.length; ++i) {
|
||||
const isImage = files[i].type.match(/image./);
|
||||
if ((isImage && !app.user.privileges['upload:post:image']) || (!isImage && !app.user.privileges['upload:post:file'])) {
|
||||
return alerts.error('[[error:no-privileges]]');
|
||||
}
|
||||
if (files[i].size > parseInt(config.maximumFileSize, 10) * 1024) {
|
||||
options.uploadForm[0].reset();
|
||||
return alerts.error('[[error:file-too-big, ' + config.maximumFileSize + ']]');
|
||||
}
|
||||
}
|
||||
const alert_id = Date.now();
|
||||
options.uploadForm.off('submit').on('submit', function () {
|
||||
$(this).ajaxSubmit({
|
||||
headers: {
|
||||
'x-csrf-token': config.csrf_token,
|
||||
},
|
||||
resetForm: true,
|
||||
clearForm: true,
|
||||
formData: options.upload.formData,
|
||||
error: function (xhr) {
|
||||
let errorMsg = (xhr.responseJSON &&
|
||||
(xhr.responseJSON.error || (xhr.responseJSON.status && xhr.responseJSON.status.message))) ||
|
||||
'[[error:parse-error]]';
|
||||
|
||||
if (xhr && xhr.status === 413) {
|
||||
errorMsg = xhr.statusText || 'Request Entity Too Large';
|
||||
}
|
||||
alerts.error(errorMsg);
|
||||
alerts.remove(alert_id);
|
||||
},
|
||||
|
||||
uploadProgress: function (event, position, total, percent) {
|
||||
alerts.alert({
|
||||
alert_id: alert_id,
|
||||
message: '[[modules:composer.uploading, ' + percent + '%]]',
|
||||
});
|
||||
},
|
||||
|
||||
success: function (res) {
|
||||
const uploads = res.response.images;
|
||||
if (uploads && uploads.length) {
|
||||
for (var i = 0; i < uploads.length; ++i) {
|
||||
uploads[i].filename = files[i].name;
|
||||
uploads[i].isImage = /image./.test(files[i].type);
|
||||
}
|
||||
}
|
||||
options.callback(uploads);
|
||||
},
|
||||
|
||||
complete: function () {
|
||||
options.uploadForm[0].reset();
|
||||
setTimeout(alerts.remove, 100, alert_id);
|
||||
},
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
options.uploadForm.submit();
|
||||
};
|
||||
|
||||
return uploadHelpers;
|
||||
});
|
||||
Reference in New Issue
Block a user