Merge branch 'master' of github.com:designcreateplay/NodeBB

fixing missing height in post-window, removed for some reason

Conflicts:
	public/src/modules/composer.js
v1.18.x
Julian Lam 12 years ago
commit 81cfe0c8d0

@ -18,9 +18,9 @@
"emailjs": "0.3.4", "emailjs": "0.3.4",
"cookie": "0.0.6", "cookie": "0.0.6",
"connect-redis": "1.4.5", "connect-redis": "1.4.5",
"passport": "0.1.16", "passport": "0.1.17",
"passport-local": "0.1.6", "passport-local": "0.1.6",
"passport-twitter": "0.1.4", "passport-twitter": "0.1.5",
"passport-google-oauth": "0.1.5", "passport-google-oauth": "0.1.5",
"passport-facebook": "0.1.5", "passport-facebook": "0.1.5",
"less-middleware": "0.1.12", "less-middleware": "0.1.12",

@ -504,8 +504,8 @@ body .navbar .nodebb-inline-block {
.post-window { .post-window {
position: fixed; position: fixed;
bottom: 45px; bottom: 45px;
height: 450px;
display: none; display: none;
height: 450px;
> div { > div {
position: absolute; position: absolute;
@ -528,7 +528,7 @@ body .navbar .nodebb-inline-block {
input { input {
width: 100%; width: 100%;
text-align: center; text-align: center;
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.5);
border: none; border: none;
padding: 0.5em 0; padding: 0.5em 0;
-webkit-border-radius: 0px; -webkit-border-radius: 0px;
@ -547,6 +547,29 @@ body .navbar .nodebb-inline-block {
color: white; color: white;
height: 330px; 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;
}
}
} }
} }

@ -48,6 +48,10 @@
padding: 2px 5px 0 5px; padding: 2px 5px 0 5px;
word-wrap: break-word; word-wrap: break-word;
} }
.post-images{
padding: 2px 5px 0 5px;
}
.post-block { .post-block {
.post-buttons { .post-buttons {

@ -7,10 +7,88 @@ define(['taskbar'], function(taskbar) {
postContainer: undefined, 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">&times;</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() { composer.init = function() {
if (!composer.initialized) { if (!composer.initialized) {
// Create the fixed bottom bar var taskbar = document.getElementById('taskbar');
var taskbar = document.getElementById('taskbar');
composer.postContainer = document.createElement('div'); composer.postContainer = document.createElement('div');
composer.postContainer.className = 'post-window row-fluid'; composer.postContainer.className = 'post-window row-fluid';
@ -29,14 +107,17 @@ define(['taskbar'], function(taskbar) {
'<button class="btn" data-action="discard" tabIndex="5"><i class="icon-remove"></i> Discard</button>' + '<button class="btn" data-action="discard" tabIndex="5"><i class="icon-remove"></i> Discard</button>' +
'</div>' + '</div>' +
'</div>' + '</div>' +
'<div id="imagedrop" style="display:none;"></div>'+
'<textarea tabIndex="2"></textarea>' + '<textarea tabIndex="2"></textarea>' +
'</div>'; '</div>';
document.body.insertBefore(composer.postContainer, taskbar); document.body.insertBefore(composer.postContainer, taskbar);
initializeFileReader();
socket.on('api:composer.push', function(threadData) { socket.on('api:composer.push', function(threadData) {
if (!threadData.error) { if (!threadData.error) {
var uuid = utils.generateUUID(); var uuid = utils.generateUUID();
composer.taskbar.push('composer', uuid, { composer.taskbar.push('composer', uuid, {
title: (!threadData.cid ? (threadData.title || '') : 'New Topic'), title: (!threadData.cid ? (threadData.title || '') : 'New Topic'),
@ -48,7 +129,8 @@ define(['taskbar'], function(taskbar) {
cid: threadData.cid, cid: threadData.cid,
pid: threadData.pid, pid: threadData.pid,
title: threadData.title || '', title: threadData.title || '',
body: threadData.body || '' body: threadData.body || '',
images: []
}; };
composer.load(uuid); composer.load(uuid);
} else { } else {
@ -156,15 +238,18 @@ define(['taskbar'], function(taskbar) {
} }
composer.load = function(post_uuid) { composer.load = function(post_uuid) {
var post_data = composer.posts[post_uuid], var post_data = composer.posts[post_uuid],
titleEl = composer.postContainer.querySelector('input'), titleEl = composer.postContainer.querySelector('input'),
bodyEl = composer.postContainer.querySelector('textarea'), bodyEl = composer.postContainer.querySelector('textarea'),
postWindowEl = composer.postContainer.querySelector('.span5'), postWindowEl = composer.postContainer.querySelector('.span5'),
taskbarBtn = document.querySelector('#taskbar [data-uuid="' + post_uuid + '"]'), taskbarBtn = document.querySelector('#taskbar [data-uuid="' + post_uuid + '"]'),
btnRect = taskbarBtn.getBoundingClientRect(), btnRect = taskbarBtn.getBoundingClientRect(),
taskbarRect = document.getElementById('taskbar').getBoundingClientRect(), taskbarRect = document.getElementById('taskbar').getBoundingClientRect(),
dropDiv = $(composer.postContainer).find('#imagedrop'),
windowRect, leftPos; windowRect, leftPos;
dropDiv.html('Drag and drop images here').hide();
composer.postContainer.style.display = 'block'; composer.postContainer.style.display = 'block';
windowRect = postWindowEl.getBoundingClientRect(); windowRect = postWindowEl.getBoundingClientRect();
leftPos = btnRect.left + btnRect.width - windowRect.width; leftPos = btnRect.left + btnRect.width - windowRect.width;
@ -184,6 +269,8 @@ define(['taskbar'], function(taskbar) {
} }
bodyEl.value = post_data.body bodyEl.value = post_data.body
// Direct user focus to the correct element // Direct user focus to the correct element
if ((parseInt(post_data.tid) || parseInt(post_data.pid)) > 0) { if ((parseInt(post_data.tid) || parseInt(post_data.pid)) > 0) {
bodyEl.focus(); bodyEl.focus();
@ -225,18 +312,21 @@ define(['taskbar'], function(taskbar) {
socket.emit('api:topics.post', { socket.emit('api:topics.post', {
'title' : titleEl.value, 'title' : titleEl.value,
'content' : bodyEl.value, 'content' : bodyEl.value,
'category_id' : postData.cid 'category_id' : postData.cid,
images: composer.posts[post_uuid].images
}); });
} else if (parseInt(postData.tid) > 0) { } else if (parseInt(postData.tid) > 0) {
socket.emit('api:posts.reply', { socket.emit('api:posts.reply', {
'topic_id' : postData.tid, 'topic_id' : postData.tid,
'content' : bodyEl.value 'content' : bodyEl.value,
images: composer.posts[post_uuid].images
}); });
} else if (parseInt(postData.pid) > 0) { } else if (parseInt(postData.pid) > 0) {
socket.emit('api:posts.edit', { socket.emit('api:posts.edit', {
pid: postData.pid, pid: postData.pid,
content: bodyEl.value, content: bodyEl.value,
title: titleEl.value title: titleEl.value,
images: composer.posts[post_uuid].images
}); });
} }
@ -245,6 +335,7 @@ define(['taskbar'], function(taskbar) {
composer.discard = function(post_uuid) { composer.discard = function(post_uuid) {
if (composer.posts[post_uuid]) { if (composer.posts[post_uuid]) {
$(composer.postContainer).find('#imagedrop').html('');
delete composer.posts[post_uuid]; delete composer.posts[post_uuid];
composer.minimize(); composer.minimize();
taskbar.discard('composer', post_uuid); taskbar.discard('composer', post_uuid);

@ -53,6 +53,11 @@
<div style="clear:both; margin-bottom: 10px;"></div> <div style="clear:both; margin-bottom: 10px;"></div>
<div id="content_{main_posts.pid}" class="post-content">{main_posts.content}</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="post-signature">{main_posts.signature}</div>
<div class="profile-block"> <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 <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="span11">
<div class="post-block"> <div class="post-block">
<div id="content_{posts.pid}" class="post-content">{posts.content}</div> <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="post-signature">{posts.signature}</div>
<div class="profile-block"> <div class="profile-block">
<span class="post-buttons"> <span class="post-buttons">

@ -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));

@ -117,6 +117,11 @@ marked.setOptions({
postData['edited-class'] = postData.editor !== '' ? '' : 'none'; postData['edited-class'] = postData.editor !== '' ? '' : 'none';
postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : ''; postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : '';
postData.content = marked(postData.content || ''); postData.content = marked(postData.content || '');
if(postData.uploadedImages) {
postData.uploadedImages = JSON.parse(postData.uploadedImages);
} else {
postData.uploadedImages = [];
}
posts.push(postData); posts.push(postData);
} }
callback(null); 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) { if (uid < 1) {
socket.emit('event:alert', { socket.emit('event:alert', {
title: 'Reply Unsuccessful', title: 'Reply Unsuccessful',
@ -211,13 +216,13 @@ marked.setOptions({
return; return;
} }
Posts.create(uid, tid, content, function(pid) { Posts.create(uid, tid, content, images, function(postData) {
if (pid > 0) { if (postData) {
RDB.rpush('tid:' + tid + ':posts', pid); RDB.rpush('tid:' + tid + ':posts', postData.pid);
RDB.del('tid:' + tid + ':read_by_uid'); 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) { RDB.del('cid:' + cid + ':read_by_uid', function(err, data) {
topics.markAsRead(tid, uid); topics.markAsRead(tid, uid);
}); });
@ -228,7 +233,6 @@ marked.setOptions({
// Send notifications to users who are following this topic // Send notifications to users who are following this topic
threadTools.notify_followers(tid, uid); threadTools.notify_followers(tid, uid);
socket.emit('event:alert', { socket.emit('event:alert', {
title: 'Reply Successful', title: 'Reply Successful',
message: 'You have successfully replied. Click here to view your reply.', message: 'You have successfully replied. Click here to view your reply.',
@ -236,21 +240,16 @@ marked.setOptions({
timeout: 2000 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 = { var socketData = {
'posts' : [ 'posts' : [
{ postData
'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': '',
}
] ]
}; };
@ -258,6 +257,7 @@ marked.setOptions({
io.sockets.in('topic_' + tid).emit('event:new_post', socketData); io.sockets.in('topic_' + tid).emit('event:new_post', socketData);
io.sockets.in('recent_posts').emit('event:new_post', socketData); io.sockets.in('recent_posts').emit('event:new_post', socketData);
}); });
} else { } else {
socket.emit('event:alert', { socket.emit('event:alert', {
@ -270,10 +270,10 @@ marked.setOptions({
}); });
}); });
}; };
Posts.create = function(uid, tid, content, callback) { Posts.create = function(uid, tid, content, images, callback) {
if (uid === null) { if (uid === null) {
callback(-1); callback(null);
return; return;
} }
@ -285,7 +285,7 @@ marked.setOptions({
var timestamp = Date.now(); var timestamp = Date.now();
RDB.hmset('post:' + pid, { var postData = {
'pid': pid, 'pid': pid,
'uid': uid, 'uid': uid,
'tid': tid, 'tid': tid,
@ -294,8 +294,11 @@ marked.setOptions({
'reputation': 0, 'reputation': 0,
'editor': '', 'editor': '',
'edited': 0, 'edited': 0,
'deleted': 0 'deleted': 0,
}); 'uploadedImages': ''
};
RDB.hmset('post:' + pid, postData);
topics.increasePostCount(tid); topics.increasePostCount(tid);
topics.updateTimestamp(tid, timestamp); topics.updateTimestamp(tid, timestamp);
@ -321,11 +324,42 @@ marked.setOptions({
user.onNewPostMade(uid, tid, pid, timestamp); user.onNewPostMade(uid, tid, pid, timestamp);
if (callback) var imgur = require('./imgur');
callback(pid); // 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 { } else {
callback(-1); callback(null);
} }
}); });
} }

@ -5,7 +5,7 @@
passportGoogle = require('passport-google-oauth').OAuth2Strategy, passportGoogle = require('passport-google-oauth').OAuth2Strategy,
passportFacebook = require('passport-facebook').Strategy, passportFacebook = require('passport-facebook').Strategy,
login_strategies = [], login_strategies = [],
nconf = require('nconf'),
user_module = require('./../user.js'), user_module = require('./../user.js'),
login_module = require('./../login.js'); login_module = require('./../login.js');
@ -20,7 +20,7 @@
passport.use(new passportTwitter({ passport.use(new passportTwitter({
consumerKey: global.config['social:twitter:key'], consumerKey: global.config['social:twitter:key'],
consumerSecret: global.config['social:twitter:secret'], consumerSecret: global.config['social:twitter:secret'],
callbackURL: config.url + 'auth/twitter/callback' callbackURL: nconf.get('url') + 'auth/twitter/callback'
}, function(token, tokenSecret, profile, done) { }, function(token, tokenSecret, profile, done) {
login_module.loginViaTwitter(profile.id, profile.username, function(err, user) { login_module.loginViaTwitter(profile.id, profile.username, function(err, user) {
if (err) { return done(err); } if (err) { return done(err); }
@ -35,7 +35,7 @@
passport.use(new passportGoogle({ passport.use(new passportGoogle({
clientID: global.config['social:google:id'], clientID: global.config['social:google:id'],
clientSecret: global.config['social:google:secret'], clientSecret: global.config['social:google:secret'],
callbackURL: config.url + 'auth/google/callback' callbackURL: nconf.get('url') + 'auth/google/callback'
}, function(accessToken, refreshToken, profile, done) { }, function(accessToken, refreshToken, profile, done) {
login_module.loginViaGoogle(profile.id, profile.displayName, profile.emails[0].value, function(err, user) { login_module.loginViaGoogle(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
if (err) { return done(err); } if (err) { return done(err); }
@ -50,7 +50,7 @@
passport.use(new passportFacebook({ passport.use(new passportFacebook({
clientID: global.config['social:facebook:app_id'], clientID: global.config['social:facebook:app_id'],
clientSecret: global.config['social:facebook:secret'], clientSecret: global.config['social:facebook:secret'],
callbackURL: config.url + 'auth/facebook/callback' callbackURL: nconf.get('url') + 'auth/facebook/callback'
}, function(accessToken, refreshToken, profile, done) { }, function(accessToken, refreshToken, profile, done) {
login_module.loginViaFacebook(profile.id, profile.displayName, profile.emails[0].value, function(err, user) { login_module.loginViaFacebook(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
if (err) { return done(err); } if (err) { return done(err); }

@ -116,7 +116,7 @@ marked.setOptions({
privileges = results[2]; privileges = results[2];
var main_posts = topicPosts.splice(0, 1); var main_posts = topicPosts.splice(0, 1);
callback(null, { callback(null, {
'topic_name':topicData.title, 'topic_name':topicData.title,
'category_name':topicData.category_name, 'category_name':topicData.category_name,
@ -313,7 +313,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) if (!category_id)
throw new Error('Attempted to post without a category_id'); throw new Error('Attempted to post without a category_id');
@ -379,9 +379,9 @@ marked.setOptions({
RDB.set('topicslug:' + slug + ':tid', tid); RDB.set('topicslug:' + slug + ':tid', tid);
posts.create(uid, tid, content, function(pid) { posts.create(uid, tid, content, images, function(postData) {
if (pid > 0) { if (postData) {
RDB.lpush(schema.topics(tid).posts, pid); RDB.lpush(schema.topics(tid).posts, postData.pid);
// Auto-subscribe the post creator to the newly created topic // Auto-subscribe the post creator to the newly created topic
threadTools.toggleFollow(tid, uid); threadTools.toggleFollow(tid, uid);

@ -169,7 +169,7 @@ var express = require('express'),
app.get('/topic/:topic_id/:slug?', function(req, res) { app.get('/topic/:topic_id/:slug?', function(req, res) {
var tid = req.params.topic_id; var tid = req.params.topic_id;
if (tid.match('^\d+\.rss$')) { if (tid.match(/^\d+\.rss$/)) {
fs.readFile('feeds/topics/' + tid, function (err, data) { fs.readFile('feeds/topics/' + tid, function (err, data) {
if (err) { if (err) {
res.type('text').send(404, "Unable to locate an rss feed at this location."); res.type('text').send(404, "Unable to locate an rss feed at this location.");
@ -181,7 +181,6 @@ var express = require('express'),
return; return;
} }
var topic_url = tid + (req.params.slug ? '/' + req.params.slug : ''); var topic_url = tid + (req.params.slug ? '/' + req.params.slug : '');
topics.getTopicWithPosts(tid, ((req.user) ? req.user.uid : 0), function(err, topic) { topics.getTopicWithPosts(tid, ((req.user) ? req.user.uid : 0), function(err, topic) {
if (err) return res.redirect('404'); if (err) return res.redirect('404');
@ -197,7 +196,8 @@ var express = require('express'),
app.get('/category/:category_id/:slug?', function(req, res) { app.get('/category/:category_id/:slug?', function(req, res) {
var cid = req.params.category_id; var cid = req.params.category_id;
if (cid.match('^\d+\.rss$')) {
if (cid.match(/^\d+\.rss$/)) {
fs.readFile('feeds/categories/' + cid, function (err, data) { fs.readFile('feeds/categories/' + cid, function (err, data) {
if (err) { if (err) {
res.type('text').send(404, "Unable to locate an rss feed at this location."); res.type('text').send(404, "Unable to locate an rss feed at this location.");

@ -313,11 +313,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
}); });
socket.on('api:topics.post', function(data) { 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) { 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() { socket.on('api:user.active.get', function() {

Loading…
Cancel
Save