mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 11:35:55 +01:00
drag and drop image upload first pass
This commit is contained in:
@@ -504,7 +504,6 @@ body .navbar .nodebb-inline-block {
|
||||
.post-window {
|
||||
position: fixed;
|
||||
bottom: 45px;
|
||||
height: 450px;
|
||||
display: none;
|
||||
|
||||
> div {
|
||||
@@ -542,6 +541,29 @@ body .navbar .nodebb-inline-block {
|
||||
color: white;
|
||||
height: 330px;
|
||||
}
|
||||
|
||||
#imagedrop {
|
||||
background: rgba(64, 64, 64, 0.95);
|
||||
padding: 0.5em;
|
||||
display: block;
|
||||
width: 90%;
|
||||
min-height:25px;
|
||||
margin: 1em auto;
|
||||
resize: none;
|
||||
color:white;
|
||||
font-size:20px;
|
||||
div {
|
||||
margin-right:10px;
|
||||
}
|
||||
span {
|
||||
line-height:20px;
|
||||
float:left;
|
||||
}
|
||||
button {
|
||||
padding-left:5px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.post-images{
|
||||
padding: 2px 5px 0 5px;
|
||||
}
|
||||
|
||||
.post-block {
|
||||
.post-buttons {
|
||||
font-size: 12px;
|
||||
|
||||
@@ -7,9 +7,87 @@ define(['taskbar'], function(taskbar) {
|
||||
postContainer: undefined,
|
||||
};
|
||||
|
||||
function loadFile(file) {
|
||||
var reader = new FileReader();
|
||||
var dropDiv = $('#imagedrop');
|
||||
var uuid = dropDiv.parents('[data-uuid]').attr('data-uuid');
|
||||
var posts = composer.posts[uuid];
|
||||
|
||||
$(reader).on('loadend', function(e) {
|
||||
var bin = this.result;
|
||||
bin = bin.split(',')[1];
|
||||
|
||||
var img = {
|
||||
name: file.name,
|
||||
data: bin
|
||||
};
|
||||
|
||||
posts.images.push(img);
|
||||
|
||||
var imageLabel = $('<div class="label"><span>'+ file.name +'</span></div>');
|
||||
var closeButton = $('<button class="close">×</button>');
|
||||
closeButton.on('click', function(e) {
|
||||
|
||||
imageLabel.remove();
|
||||
var index = posts.images.indexOf(img);
|
||||
if(index !== -1) {
|
||||
posts.images.splice(index, 1);
|
||||
}
|
||||
|
||||
if(!dropDiv.children().length) {
|
||||
dropDiv.html('Drag and drop images here');
|
||||
}
|
||||
});
|
||||
|
||||
imageLabel.append(closeButton);
|
||||
dropDiv.append(imageLabel);
|
||||
|
||||
});
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function initializeFileReader() {
|
||||
jQuery.event.props.push( "dataTransfer" );
|
||||
|
||||
if(window.FileReader) {
|
||||
var drop = $('#imagedrop');
|
||||
|
||||
$(composer.postContainer).on('dragenter dragover', function() {
|
||||
drop.show();
|
||||
});
|
||||
|
||||
function cancel(e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
drop.on('dragover', cancel);
|
||||
drop.on('dragenter', cancel);
|
||||
|
||||
drop.on('drop', function(e) {
|
||||
e.preventDefault();
|
||||
var uuid = drop.parents('[data-uuid]').attr('data-uuid');
|
||||
var posts = composer.posts[uuid];
|
||||
|
||||
var dt = e.dataTransfer;
|
||||
var files = dt.files;
|
||||
|
||||
if(!posts.images.length)
|
||||
drop.html('');
|
||||
|
||||
for (var i=0; i<files.length; i++) {
|
||||
loadFile(files[i]);
|
||||
}
|
||||
return false;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
composer.init = function() {
|
||||
if (!composer.initialized) {
|
||||
// Create the fixed bottom bar
|
||||
var taskbar = document.getElementById('taskbar');
|
||||
|
||||
composer.postContainer = document.createElement('div');
|
||||
@@ -29,11 +107,14 @@ define(['taskbar'], function(taskbar) {
|
||||
'<button class="btn" data-action="discard" tabIndex="5"><i class="icon-remove"></i> Discard</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div id="imagedrop" style="display:none;"></div>'+
|
||||
'<textarea tabIndex="2"></textarea>' +
|
||||
'</div>';
|
||||
|
||||
document.body.insertBefore(composer.postContainer, taskbar);
|
||||
|
||||
initializeFileReader();
|
||||
|
||||
socket.on('api:composer.push', function(threadData) {
|
||||
if (!threadData.error) {
|
||||
var uuid = utils.generateUUID();
|
||||
@@ -48,7 +129,8 @@ define(['taskbar'], function(taskbar) {
|
||||
cid: threadData.cid,
|
||||
pid: threadData.pid,
|
||||
title: threadData.title || '',
|
||||
body: threadData.body || ''
|
||||
body: threadData.body || '',
|
||||
images: []
|
||||
};
|
||||
composer.load(uuid);
|
||||
} else {
|
||||
@@ -158,7 +240,10 @@ define(['taskbar'], function(taskbar) {
|
||||
composer.load = function(post_uuid) {
|
||||
var post_data = composer.posts[post_uuid],
|
||||
titleEl = composer.postContainer.querySelector('input'),
|
||||
bodyEl = composer.postContainer.querySelector('textarea');
|
||||
bodyEl = composer.postContainer.querySelector('textarea'),
|
||||
dropDiv = $(composer.postContainer).find('#imagedrop');
|
||||
|
||||
dropDiv.html('Drag and drop images here').hide();
|
||||
|
||||
composer.postContainer.style.display = 'block';
|
||||
// composer.postContainer.style.bottom = composer.btnContainer.offsetHeight + "px";
|
||||
@@ -176,6 +261,8 @@ define(['taskbar'], function(taskbar) {
|
||||
}
|
||||
bodyEl.value = post_data.body
|
||||
|
||||
|
||||
|
||||
// Direct user focus to the correct element
|
||||
if ((parseInt(post_data.tid) || parseInt(post_data.pid)) > 0) {
|
||||
bodyEl.focus();
|
||||
@@ -217,18 +304,21 @@ define(['taskbar'], function(taskbar) {
|
||||
socket.emit('api:topics.post', {
|
||||
'title' : titleEl.value,
|
||||
'content' : bodyEl.value,
|
||||
'category_id' : postData.cid
|
||||
'category_id' : postData.cid,
|
||||
images: composer.posts[post_uuid].images
|
||||
});
|
||||
} else if (parseInt(postData.tid) > 0) {
|
||||
socket.emit('api:posts.reply', {
|
||||
'topic_id' : postData.tid,
|
||||
'content' : bodyEl.value
|
||||
'content' : bodyEl.value,
|
||||
images: composer.posts[post_uuid].images
|
||||
});
|
||||
} else if (parseInt(postData.pid) > 0) {
|
||||
socket.emit('api:posts.edit', {
|
||||
pid: postData.pid,
|
||||
content: bodyEl.value,
|
||||
title: titleEl.value
|
||||
title: titleEl.value,
|
||||
images: composer.posts[post_uuid].images
|
||||
});
|
||||
}
|
||||
|
||||
@@ -237,6 +327,7 @@ define(['taskbar'], function(taskbar) {
|
||||
|
||||
composer.discard = function(post_uuid) {
|
||||
if (composer.posts[post_uuid]) {
|
||||
$(composer.postContainer).find('#imagedrop').html('');
|
||||
delete composer.posts[post_uuid];
|
||||
composer.minimize();
|
||||
taskbar.discard('composer', post_uuid);
|
||||
|
||||
@@ -53,6 +53,11 @@
|
||||
<div style="clear:both; margin-bottom: 10px;"></div>
|
||||
|
||||
<div id="content_{main_posts.pid}" class="post-content">{main_posts.content}</div>
|
||||
<div id="images_{main_posts.pid}" class="post-images">
|
||||
<!-- BEGIN uploadedImages -->
|
||||
<i class="icon-picture icon-1"></i><a href="{main_posts.uploadedImages.url}"> {main_posts.uploadedImages.name}</a><br/>
|
||||
<!-- END uploadedImages -->
|
||||
</div>
|
||||
<div class="post-signature">{main_posts.signature}</div>
|
||||
<div class="profile-block">
|
||||
<img class="hidden-desktop" src="{main_posts.picture}?s=10&default=identicon" align="left" /> posted by <strong><a class="" href="/users/{main_posts.userslug}">{main_posts.username}</a></strong> {main_posts.relativeTime} ago
|
||||
@@ -81,6 +86,11 @@
|
||||
<div class="span11">
|
||||
<div class="post-block">
|
||||
<div id="content_{posts.pid}" class="post-content">{posts.content}</div>
|
||||
<div id="images_{posts.pid}" class="post-images">
|
||||
<!-- BEGIN uploadedImages -->
|
||||
<i class="icon-picture icon-1"></i><a href="{posts.uploadedImages.url}"> {posts.uploadedImages.name}</a><br/>
|
||||
<!-- END uploadedImages -->
|
||||
</div>
|
||||
<div class="post-signature">{posts.signature}</div>
|
||||
<div class="profile-block">
|
||||
<span class="post-buttons">
|
||||
|
||||
33
src/imgur.js
Normal file
33
src/imgur.js
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
var request = require('request');
|
||||
|
||||
|
||||
(function(imgur) {
|
||||
var clientID = '';
|
||||
|
||||
imgur.upload = function(image, type, callback) {
|
||||
var options = {
|
||||
url: 'https://api.imgur.com/3/upload.json',
|
||||
headers: {
|
||||
'Authorization': 'Client-ID ' + clientID
|
||||
}
|
||||
};
|
||||
|
||||
var post = request.post(options, function(err, req, body){
|
||||
try{
|
||||
callback(err, JSON.parse(body));
|
||||
} catch(e) {
|
||||
callback(err, body);
|
||||
}
|
||||
});
|
||||
|
||||
var upload = post.form({type:type, image:image});
|
||||
}
|
||||
|
||||
imgur.setClientID = function(id) {
|
||||
clientID = id;
|
||||
}
|
||||
|
||||
}(exports));
|
||||
|
||||
86
src/posts.js
86
src/posts.js
@@ -117,6 +117,11 @@ marked.setOptions({
|
||||
postData['edited-class'] = postData.editor !== '' ? '' : 'none';
|
||||
postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : '';
|
||||
postData.content = marked(postData.content || '');
|
||||
if(postData.uploadedImages) {
|
||||
postData.uploadedImages = JSON.parse(postData.uploadedImages);
|
||||
} else {
|
||||
postData.uploadedImages = [];
|
||||
}
|
||||
posts.push(postData);
|
||||
}
|
||||
callback(null);
|
||||
@@ -185,7 +190,7 @@ marked.setOptions({
|
||||
});
|
||||
}
|
||||
|
||||
Posts.reply = function(socket, tid, uid, content) {
|
||||
Posts.reply = function(socket, tid, uid, content, images) {
|
||||
if (uid < 1) {
|
||||
socket.emit('event:alert', {
|
||||
title: 'Reply Unsuccessful',
|
||||
@@ -211,13 +216,13 @@ marked.setOptions({
|
||||
return;
|
||||
}
|
||||
|
||||
Posts.create(uid, tid, content, function(pid) {
|
||||
if (pid > 0) {
|
||||
RDB.rpush('tid:' + tid + ':posts', pid);
|
||||
Posts.create(uid, tid, content, images, function(postData) {
|
||||
if (postData) {
|
||||
RDB.rpush('tid:' + tid + ':posts', postData.pid);
|
||||
|
||||
RDB.del('tid:' + tid + ':read_by_uid');
|
||||
|
||||
Posts.get_cid_by_pid(pid, function(cid) {
|
||||
Posts.get_cid_by_pid(postData.pid, function(cid) {
|
||||
RDB.del('cid:' + cid + ':read_by_uid', function(err, data) {
|
||||
topics.markAsRead(tid, uid);
|
||||
});
|
||||
@@ -228,7 +233,6 @@ marked.setOptions({
|
||||
// Send notifications to users who are following this topic
|
||||
threadTools.notify_followers(tid, uid);
|
||||
|
||||
|
||||
socket.emit('event:alert', {
|
||||
title: 'Reply Successful',
|
||||
message: 'You have successfully replied. Click here to view your reply.',
|
||||
@@ -236,21 +240,16 @@ marked.setOptions({
|
||||
timeout: 2000
|
||||
});
|
||||
|
||||
postData.content = marked(postData.content);
|
||||
postData.post_rep = 0;
|
||||
postData.relativeTime = utils.relativeTime(postData.timestamp)
|
||||
postData.fav_star_class = 'icon-star-empty';
|
||||
postData['edited-class'] = 'none';
|
||||
postData.uploadedImages = JSON.parse(postData.uploadedImages);
|
||||
|
||||
var timestamp = Date.now();
|
||||
var socketData = {
|
||||
'posts' : [
|
||||
{
|
||||
'pid' : pid,
|
||||
'content' : marked(content || ''),
|
||||
'uid' : uid,
|
||||
'post_rep' : 0,
|
||||
'timestamp' : timestamp,
|
||||
'relativeTime': utils.relativeTime(timestamp),
|
||||
'fav_star_class' :'icon-star-empty',
|
||||
'edited-class': 'none',
|
||||
'editor': '',
|
||||
}
|
||||
postData
|
||||
]
|
||||
};
|
||||
|
||||
@@ -259,6 +258,7 @@ marked.setOptions({
|
||||
io.sockets.in('recent_posts').emit('event:new_post', socketData);
|
||||
});
|
||||
|
||||
|
||||
} else {
|
||||
socket.emit('event:alert', {
|
||||
title: 'Reply Unsuccessful',
|
||||
@@ -271,9 +271,9 @@ marked.setOptions({
|
||||
});
|
||||
};
|
||||
|
||||
Posts.create = function(uid, tid, content, callback) {
|
||||
Posts.create = function(uid, tid, content, images, callback) {
|
||||
if (uid === null) {
|
||||
callback(-1);
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ marked.setOptions({
|
||||
|
||||
var timestamp = Date.now();
|
||||
|
||||
RDB.hmset('post:' + pid, {
|
||||
var postData = {
|
||||
'pid': pid,
|
||||
'uid': uid,
|
||||
'tid': tid,
|
||||
@@ -294,8 +294,11 @@ marked.setOptions({
|
||||
'reputation': 0,
|
||||
'editor': '',
|
||||
'edited': 0,
|
||||
'deleted': 0
|
||||
});
|
||||
'deleted': 0,
|
||||
'uploadedImages': ''
|
||||
};
|
||||
|
||||
RDB.hmset('post:' + pid, postData);
|
||||
|
||||
topics.increasePostCount(tid);
|
||||
topics.updateTimestamp(tid, timestamp);
|
||||
@@ -321,11 +324,42 @@ marked.setOptions({
|
||||
|
||||
user.onNewPostMade(uid, tid, pid, timestamp);
|
||||
|
||||
if (callback)
|
||||
callback(pid);
|
||||
var imgur = require('./imgur');
|
||||
// move clientID to config
|
||||
imgur.setClientID('09f3955fee9a0a6');
|
||||
|
||||
var uploadedImages = [];
|
||||
|
||||
function uploadImage(image, callback) {
|
||||
imgur.upload(image.data, 'base64', function(err, data) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
} else {
|
||||
if(data.success) {
|
||||
var img= {url:data.data.link, name:image.name};
|
||||
uploadedImages.push(img);
|
||||
callback(null);
|
||||
} else {
|
||||
callback(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async.each(images, uploadImage, function(err) {
|
||||
if(!err) {
|
||||
postData.uploadedImages = JSON.stringify(uploadedImages);
|
||||
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
|
||||
|
||||
callback(postData);
|
||||
} else {
|
||||
console.log(err);
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
callback(-1);
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -117,6 +117,10 @@ marked.setOptions({
|
||||
|
||||
var main_posts = topicPosts.splice(0, 1);
|
||||
|
||||
/* main_posts[0].main_uploadedImages = main_posts[0].uploadedImages;
|
||||
delete main_posts[0].uploadedImages;
|
||||
console.log(main_posts);*/
|
||||
|
||||
callback(null, {
|
||||
'topic_name':topicData.title,
|
||||
'category_name':topicData.category_name,
|
||||
@@ -313,7 +317,7 @@ marked.setOptions({
|
||||
});
|
||||
}
|
||||
|
||||
Topics.post = function(socket, uid, title, content, category_id) {
|
||||
Topics.post = function(socket, uid, title, content, category_id, images) {
|
||||
if (!category_id)
|
||||
throw new Error('Attempted to post without a category_id');
|
||||
|
||||
@@ -379,9 +383,9 @@ marked.setOptions({
|
||||
|
||||
RDB.set('topicslug:' + slug + ':tid', tid);
|
||||
|
||||
posts.create(uid, tid, content, function(pid) {
|
||||
if (pid > 0) {
|
||||
RDB.lpush(schema.topics(tid).posts, pid);
|
||||
posts.create(uid, tid, content, images, function(postData) {
|
||||
if (postData) {
|
||||
RDB.lpush(schema.topics(tid).posts, postData.pid);
|
||||
|
||||
// Auto-subscribe the post creator to the newly created topic
|
||||
threadTools.toggleFollow(tid, uid);
|
||||
|
||||
@@ -313,11 +313,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
||||
});
|
||||
|
||||
socket.on('api:topics.post', function(data) {
|
||||
topics.post(socket, uid, data.title, data.content, data.category_id);
|
||||
topics.post(socket, uid, data.title, data.content, data.category_id, data.images);
|
||||
});
|
||||
|
||||
socket.on('api:posts.reply', function(data) {
|
||||
posts.reply(socket, data.topic_id, uid, data.content);
|
||||
posts.reply(socket, data.topic_id, uid, data.content, data.images);
|
||||
});
|
||||
|
||||
socket.on('api:user.active.get', function() {
|
||||
|
||||
Reference in New Issue
Block a user